2015-11-06 11 views
8

XMLを操作しながらコメントを可能な限り忠実に保持したいと思います。パーサされたXML(Python 2.7)のコメントを忠実に保持

私はコメントを保存することができましたが、内容は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) 

#!/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') 
しかし、などのようなコメント:

<!-- 
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.pyself._target.data(saxutils.unescape(data))を試してみましたが、何もしていないようでした。実際、問題はhandle_commment()のステップの後のどこかで発生すると思います。

ところで、この質問はthisに似ています。

答えて

8

Python 2.7および3.5でテストした場合、次のコードは意図したとおりに動作するはずです。代わりに、現在の一方のパーサとして

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

class CommentedTreeBuilder(ElementTree.TreeBuilder): 
    def __init__(self, *args, **kwargs): 
     super(CommentedTreeBuilder, self).__init__(*args, **kwargs) 

    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) 

のいずれも必要なくなります。

+0

どちらの解決策もコメントを保存しているようですね、ありがとう!しかし、他の要素は再フォーマットされます(属性は並べ替えられ、潜在的に再配列されます)。私はそれが機械可読性のために重要ではないことを知っていますが、私の目的(人間の可読性、バージョン管理、明示的に触れた要素に触れることのみ)に関しては重要です。 FWIW、私の元のバージョンは、他の要素を元のままにしてしまいます。この答えは私の明白な質問に対処するので、回答賞を得るでしょうが、コメントでない要素の書式の保存も可能であるかどうかを知りたいと思います。 –

+0

私が見る限り、変更されるのは属性とタグ内の空白の順序です(何か不足している場合は修正してください)。あなたは通常、後者を持っていたり、気にしてはいけません。属性は 'xml'でディクショナリに格納されているので、出力の順序はランダムです。これを修正するには、コメントと同様の回避策を使用できます(http://stackoverflow.com/q/2741480/2997179を参照)。あるいは、 'lxml'を使った簡単なテストでは、属性の順序が保持されているように見え、実行可能な解決策のようです。いずれにせよ、私はこれが別のSOの質問に値すると思う。 –

+0

さて、属性の上で、 'xml'は処理命令タグ(例えば、' <?xml-stylesheet href = "mystyle.css" type = "text/css"?> ')を破棄し、xmlns名前空間の名前を変更します。ここでも 'lxml'はどちらもしません。 –

関連する問題