web-dev-qa-db-ja.com

解析されたXMLでコメントを忠実に保存する

XMLを操作している間、コメントをできるだけ忠実に保存したいと思います。

コメントを保存することができましたが、コンテンツがXMLエスケープされています。

_#!/usr/bin/env python
# add_Host_to_Tomcat.py

import xml.etree.ElementTree as ET
from CommentedTreeBuilder import CommentedTreeBuilder
parser = CommentedTreeBuilder()

if __name__ == '__main__':
    filename = "/opt/lucee/Tomcat/conf/server.xml"

    # this is the important part: use the comment-preserving parser
    tree = ET.parse(filename, parser)

    # get the node to add a child to
    engine_node = tree.find("./Service/Engine")

    # add a node: Engine.Host
    Host_node = ET.SubElement(
        engine_node,
        "Host",
        name="local.mysite.com",
        appBase="webapps"
    )
    # add a child to new node: Engine.Host.Context
    ET.SubElement(
        Host_node,
        'Context',
        path="",
        docBase="/path/to/doc/base"
    )

    tree.write('out.xml')
_
_#!/usr/bin/env python
# CommentedTreeBuilder.py

from xml.etree import ElementTree

class CommentedTreeBuilder ( ElementTree.XMLTreeBuilder ):
    def __init__ ( self, html = 0, target = None ):
        ElementTree.XMLTreeBuilder.__init__( self, html, target )
        self._parser.CommentHandler = self.handle_comment

    def handle_comment ( self, data ):
        self._target.start( ElementTree.Comment, {} )
        self._target.data( data )
        self._target.end( ElementTree.Comment )
_

ただし、次のようなコメント:

_  <!--
EXAMPLE Host ENTRY:
    <Host name="lucee.org" appBase="webapps">
         <Context path="" docBase="/var/sites/getrailo.org" />
     <Alias>www.lucee.org</Alias>
     <Alias>my.lucee.org</Alias>
    </Host>

Host ENTRY TEMPLATE:
    <Host name="[ENTER DOMAIN NAME]" appBase="webapps">
         <Context path="" docBase="[ENTER SYSTEM PATH]" />
     <Alias>[ENTER DOMAIN ALIAS]</Alias>
    </Host>
  -->
_

最終的に:

_  <!--
            EXAMPLE Host ENTRY:
    &lt;Host name="lucee.org" appBase="webapps"&gt;
         &lt;Context path="" docBase="/var/sites/getrailo.org" /&gt;
         &lt;Alias&gt;www.lucee.org&lt;/Alias&gt;
         &lt;Alias&gt;my.lucee.org&lt;/Alias&gt;
    &lt;/Host&gt;

    Host ENTRY TEMPLATE:
    &lt;Host name="[ENTER DOMAIN NAME]" appBase="webapps"&gt;
         &lt;Context path="" docBase="[ENTER SYSTEM PATH]" /&gt;
         &lt;Alias&gt;[ENTER DOMAIN ALIAS]&lt;/Alias&gt;
    &lt;/Host&gt;
   -->
_

_CommentedTreeBuilder.py_でself._target.data( saxutils.unescape(data) )も試しましたが、何もしなかったようです。実際、問題はhandle_commment()ステップの後のどこかで発生すると思います。

ちなみに、この質問は this に似ています。

15
Jamie Jackson

Python 2.7および3.5でテストすると、次のコードは意図したとおりに機能するはずです。

#!/usr/bin/env python
# CommentedTreeBuilder.py
from xml.etree import ElementTree

class CommentedTreeBuilder(ElementTree.TreeBuilder):
    def comment(self, data):
        self.start(ElementTree.Comment, {})
        self.data(data)
        self.end(ElementTree.Comment)

次に、メインコードで使用します

parser = ET.XMLParser(target=CommentedTreeBuilder())

現在のものの代わりにパーサーとして。

ちなみに、コメントはlxmlで箱から出して正しく機能します。つまり、あなたはただすることができます

import lxml.etree as ET
tree = ET.parse(filename)

上記のいずれも必要ありません。

19
Martin Valgur

マーティンのコードは私にはうまくいきませんでした。意図したとおりに機能する以下で同じように変更しました。

import xml.etree.ElementTree as ET

class CommentedTreeBuilder(ET.XMLTreeBuilder):
    def __init__(self, *args, **kwargs):
        super(CommentedTreeBuilder, self).__init__(*args, **kwargs)
        self._parser.CommentHandler = self.comment

    def comment(self, data):
        self._target.start(ET.Comment, {})
        self._target.data(data)
        self._target.end(ET.Comment)

これはテストです

    parser=CommentedTreeBuilder()
    tree = ET.parse(filename, parser)
    tree.write('out.xml')
3
sukhbinder

@Martinと@sukhbinderの両方の回答が私には機能しなかったようです...したがって、これをpython 3.xで実行可能な完成したソリューションとして作成しました

from xml.etree import ElementTree

string = '''<?xml version="1.0"?>
<data>
    <!--Test
    -->
    <country name="Liechtenstein">
        <rank>1</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
</data>'''

class CommentedTreeBuilder(ElementTree.TreeBuilder):
    def comment(self, data):
        self.start(ElementTree.Comment, {})
        self.data(data)
        self.end(ElementTree.Comment)

parser = ElementTree.XMLParser(target=CommentedTreeBuilder())
tree = ElementTree.fromstring(string, parser)
print(tree.find("./*[0]").text)
# or ElementTree.parse(filename, parser)
1
JustWe