2009-03-19 4 views
10

Esiste un modo per mantenere l'ordine originale degli attributi durante l'elaborazione di XML con minidom?Mantieni l'ordine degli attributi durante la modifica con minidom

Dire che ho: <color red="255" green="255" blue="233" /> quando modifico questo con minidom gli attributi sono riarrangiati in ordine alfabetico blu, verde e rosso. Vorrei conservare l'ordine originale.

Sto elaborando il file eseguendo il ciclo degli elementi restituiti da elements = doc.getElementsByTagName('color') e quindi eseguo assegnazioni come questa e.attributes["red"].value = "233".

risposta

8

Esiste un modo per mantenere l'ordine originale degli attributi durante l'elaborazione di XML con minidom?

Con minidom no, il tipo di dati utilizzato per memorizzare gli attributi è un dizionario non ordinato. pxdom può farlo, anche se è notevolmente più lento.

-1

Ho finito per utilizzare la libreria lxml anziché il minidom.

+1

per fare un esempio, si veda [questo post] (http: // StackOverflow. it/a/34560411/540510) – thdox

3

È chiaro che l'attributo xml non è ordinato. Ho appena trovato questo strano comportamento!

Sembra che questo sia correlato a un ordinamento aggiunto nella funzione 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("\"") 

Rimuovere la riga ripristinare un comportamento che mantiene l'ordine del documento originale. È una buona idea quando devi verificare con strumenti diff che non ci siano errori nel tuo codice.

8

Per mantenere l'ordine attributo ho fatto questa piccola modifica nel minidom:

from collections import OrderedDict 

Nella classe Elemento:

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

Ora questo funziona solo con Python 2.7+ E sono Non sono sicuro che funzioni effettivamente => Usa a proprio rischio ...

E si noti che non si deve fare affidamento sull'ordine di attributo:

Si noti che l'ordine delle specifiche di attributo in un tag di inizio o di un elemento vuoto non è significativo.

+0

Come hai modificato t lui classe Element? – NPike

+0

Funziona ancora su Python 3.2, sostituisce 'a_names = sorted (attrs.keys())' di 'a_names = attrs.keys()' –

3

Prima di Python 2.7, ho usato seguendo HotPatching:

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()) 

Utilizzato in questo modo:

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

responsabilità:

  1. Tu non contare su ordine di attributi.
  2. muting la classe NamedNodeMap non è thread-safe.
  3. hotpatching è il male.
2

Voi ragazzi potete sopportare il maggior numero di dinieghi che volete. Mentre riordinare gli attributi non ha significato per il programma, ha un significato per il programmatore/utente.

Per Fredrick era importante avere l'ordine RGB poiché è così che l'ordine dei colori è. Per me è l'attributo name in particolare.

Confronta

<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"/> 

Contro

<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"/> 

Mentre non è impossibile leggere non è così facile. Il nome è l'attributo importante. Nascondere il campo del nome non è buono. Cosa succede se il nome era 15 attributi a sinistra, dove 7 degli attributi di fronte era facoltativo?

Il punto è che il riordino è un problema più grande di quello che fornisce l'ordine in entrata. Ha problemi con il modo in cui il programmatore pensa o come dovrebbe funzionare la funzionalità. Almeno l'ordine dovrebbe essere configurabile/facoltativo.

Scusa il mio povero inglese. Non è la mia lingua principale.

+3

Quello che stai dicendo qui non è irragionevole. Ma non è una risposta alla domanda. – mzjn

+0

non capisco –

+0

Sono assolutamente d'accordo con quello che stai dicendo, ma questo dovrebbe essere davvero un commento, anche se è troppo grande per uno. –

1

1.Custom il proprio metodo 'Element.writexml'.

da 'minidom.py' copia il codice writexml di Element nel tuo file.

rinominarlo in writexml_nosort,

delete 'a_names.sort()' (Python 2.7) o il cambiamento 'a_names = ordinati (attrs.keys())' a 'a_names = attrs.keys()' (python 3.4)

cambiamento il metodo del elemento al proprio:

minidom.Element.writexml = writexml_nosort;

2.custom nell'ordine desiderato:

right_order = [ 'a', 'b', 'c', 'A1', 'b1']

3.Adjust vostro elemento 's _attrs

node._attrs = OrderedDict ([(k, node._attrs [k]) per k in right_order])