2009-03-19 17 views
10

minidomでXMLを処理するときに属性の元の順序を保持できる方法はありますか?minidomで変更するときの属性の順序を保持

私が持っているもの:<color red="255" green="255" blue="233" /> これをminidomで変更すると、属性は青、緑、赤のアルファベット順に並べ替えられます。私は元の注文を保存したいと思います。

私はelements = doc.getElementsByTagName('color')によって返された要素をループしてファイルを処理しています。次に、e.attributes["red"].value = "233"のような割り当てを行います。

答えて

8

minidomでXMLを処理するときに元の属性の順序を保持できる方法はありますか?

minidomを指定しない場合、属性の格納に使用するデータ型は順序付けられていないディクショナリです。それはかなり遅いですが、pxdomできます。

-1

ミニドームの代わりにlxmlライブラリを使用してしまいました。

+1

を_attrs、参照[このポスト](HTTP:// stackoverflowの。 com/a/34560411/540510) – thdox

3

xml属性が順序付けられていないことは明らかです。 私はちょうどこの奇妙な行動を見つけました!

これは、xml.dom.minidom.Element.writexml関数に追加されたソートに関連しているようです!

class Element(Node): 
... snip ... 

    def writexml(self, writer, indent="", addindent="", newl=""): 
     # indent = current indentation 
     # addindent = indentation to add to higher levels 
     # newl = newline string 
     writer.write(indent+"<" + self.tagName) 

     attrs = self._get_attributes() 
     a_names = attrs.keys() 
     a_names.sort() 
--------^^^^^^^^^^^^^^ 
     for a_name in a_names: 
      writer.write(" %s=\"" % a_name) 
      _write_data(writer, attrs[a_name].value) 
      writer.write("\"") 

行を削除すると、元のドキュメントの順序を保持する動作が復元されます。 あなたのコードに間違いがないことをdiffツールで確認する必要があるときは、良い考えです。これが唯一のPython 2.7以降 で動作します今

__init__(...) 
    self._attrs = OrderedDict() 
    #self._attrs = {} 
writexml(...) 
    #a_names.sort() 

と私は思います。要素のクラスで

from collections import OrderedDict 

8

は、私はminidomで、この若干の修正を加え、属性の順序を維持するために、それが実際に働いているかどうかわからない=>あなた自身のリスクで使用する...

そして、属性の順序に頼るべきではないことに注意してください:

開始タグまたは空要素タグ内の属性指定の順序は重要ではないことに注意してください。のPython 2.7の前に、私はホットパッチ次使用

+0

どのようにしてtを修正しましたか?彼は要素クラスですか? – NPike

+0

Python 3.2でも動作します。 'a_names = sorted(attrs.keys())'を 'a_names = attrs.keys()'に置き換えます。 –

3

:この方法を使用し

class _MinidomHooker(object): 
    def __enter__(self): 
     minidom.NamedNodeMap.keys_orig = minidom.NamedNodeMap.keys 
     minidom.NamedNodeMap.keys = self._NamedNodeMap_keys_hook 
     return self 

    def __exit__(self, *args): 
     minidom.NamedNodeMap.keys = minidom.NamedNodeMap.keys_orig 
     del minidom.NamedNodeMap.keys_orig 

    @staticmethod 
    def _NamedNodeMap_keys_hook(node_map): 
     class OrderPreservingList(list): 
      def sort(self): 
       pass 
     return OrderPreservingList(node_map.keys_orig()) 

with _MinidomHooker(): 
    document.writexml(...) 

免責事項:

  1. あなたがの順序に依存してはなりません属性。
  2. NamedNodeMapクラスの変更はスレッドセーフではありません。
  3. ホットパッチは悪です。
2

あなたはあなたが望む免責条項をいくつでも付け加えることができます。 属性の順序を変更することは、プログラムにとっては意味がありませんが、プログラマー/ユーザーにとって意味があります。

フレデリックにとっては、RGBの順番を持つことが重要でした。これは、色の順序がどのようになっているかということです。 私にとっては特に名前属性です。それはのように簡単ではありません読み取ることが不可能ではないですが

<field indexed="true" multiValued="false" name="forkortelse" required="false" stored="true" type="string"/> 
<field indexed="true" multiValued="false" name="kortform" required="false" stored="true" type="text_general"/> 
<field indexed="true" multiValued="false" name="dato" required="false" stored="true" type="date"/> 
<field indexed="true" multiValued="false" name="nummer" required="false" stored="true" type="int"/> 
<field indexed="true" multiValued="false" name="kilde" required="false" stored="true" type="string"/> 
<field an_optional_attr="OMG!" an_optional_attr2="OMG!!" indexed="true" name="tittel" stored="true" type="text_general"/> 

に対する

<field name="url" type="string" indexed="true" stored="true" required="true" multiValued="false"/> <!-- ID --> 
<field name="forkortelse" type="string" indexed="true" stored="true" required="false" multiValued="false" /> 
<field name="kortform" type="text_general" indexed="true" stored="true" required="false" multiValued="false" /> 
<field name="dato" type="date" indexed="true" stored="true" required="false" multiValued="false" /> 
<field name="nummer" type="int" indexed="true" stored="true" required="false" multiValued="false" /> 
<field name="kilde" type="string" indexed="true" stored="true" required="false" multiValued="false" /> 
<field name="tittel" type="text_general" indexed="true" stored="true" multiValued="true"/> 

を比較します。名前は重要な属性です。名前フィールドの方法を後ろに隠すことは良いことではありません。名前の前にある属性のうちの7つがオプションであった場合、名前が15の属性であった場合はどうなりますか?

重要なのは、並べ替えが大きな問題であるということです。それは、プログラマーの考え方や、機能がどのように働くと思われるかを迷います。少なくとも注文は設定可能/オプションでなければなりません。

すみません。私の主な言語ではありません。

+3

あなたがここで言うことは不合理ではありません。しかし、それは質問に対する答えではありません。 – mzjn

+0

私は理解していません –

+0

あなたが言っていることに全く同意しますが、それは実際にはコメントでなければなりません。 –

1

1.独自の 'Element.writexml'メソッドをカスタマイズします。

'minidom.py'からElementのwritexmlコードを自分のファイルにコピーします。

それはwritexml_nosortし、名前の変更、

削除 'a_names.sort()'(のpython 2.7) または変更する 'a_names =ソート(attrs.keys())' 'a_namesの=のattrs.keys()' (のpython 3.4)

変更、独自の要素の方法:

minidom.Element.writexml = writexml_nosort。

2.custom好きな順:

right_order = [ 'A'、 'B'、 'C​​'、 'A1'、 'B1']あなたの要素3.adjust

「sは一例として([right_orderにおけるkに対する(K、node._attrs [K])])

node._attrs = OrderedDict

関連する問題