Python XML - создание плоской записи из динамических вложенных элементов "узла" - PullRequest
1 голос
/ 27 марта 2009

Мне нужно проанализировать файл XML и построить вывод данных на основе записей. Проблема заключается в том, что XML имеет «общую» форму, поскольку он имеет несколько уровней вложенных «узловых» элементов, которые представляют какую-то структуру данных. Мне нужно строить записи динамически на основе самого глубокого уровня элемента "узел". Некоторые примеры XML и ожидаемый результат находятся внизу.

Я самый знакомый с ElementTree в Python, поэтому я предпочел бы использовать это, но я просто не могу обернуться, чтобы динамически построить выходную запись на основе глубины динамического узла. Кроме того - мы не можем предполагать, что вложенные узлы будут иметь глубину x уровней, поэтому просто жесткое кодирование каждого уровня без цикла невозможно. Есть ли способ проанализировать XML и создать вывод на лету?

Некоторые дополнительные примечания:

  • Все имена узлов являются "узлами", кроме родительской и подробной информации (курс, цена и т. Д.)
  • Глубина узла не является статической. Итак - предположим, что уровни выше, чем показано в образце
  • Каждый «уровень» может иметь несколько подуровней. Итак, вам нужно выполнить цикл на каждом дочернем «узле», чтобы правильно построить каждую запись.

Любые идеи / вклад будет принята с благодарностью.

<root>
   <node>101
      <node>A
         <node>PlanA     
            <node>default
                <rate>100.00</rate>
            </node>
            <node>alternative
                <rate>90.00</rate>
            </node>
         </node>
      </node>
   </node>
   <node>102
      <node>B
         <node>PlanZZ     
            <node>Group 1
               <node>default
                   <rate>100.00</rate>
               </node>
               <node>alternative
                   <rate>90.00</rate>
               </node>
            </node>
            <node>Group 2
               <node>Suba
                  <node>default
                      <rate>1.00</rate>
                  </node>
                      <node>alternative
                      <rate>88.00</rate>
                  </node>
               </node>
               <node>Subb
                  <node>default
                      <rate>200.00</rate>
                  </node>
                      <node>alternative
                      <rate>4.00</rate>
                  </node>
               </node>
            </node>
         </node>
      </node>  
   </node>
</root>

Вывод будет выглядеть так:

SRV  SUB  PLAN   Group    SubGrp  DefRate   AltRate
101  A    PlanA                   100       90
102  B    PlanB  Group1           100       90
102  B    PlanB  Group2   Suba    1         88
102  B    PlanB  Group2   Subb    200       4

Ответы [ 2 ]

4 голосов
/ 27 марта 2009

Вот почему у вас есть элемент дерева элементов find с XPath.

class Plan( object ):
    def __init__( self ):
        self.srv= None
        self.sub= None
        self.plan= None
        self.group= None
        self.subgroup= None
        self.defrate= None
        self.altrate= None
    def initFrom( self, other ):
        self.srv= other.srv
        self.sub= other.sub
        self.plan= other.plan
        self.group= other.group
        self.subgroup= other.subgroup
    def __str__( self ):
        return "%s %s %s %s %s %s %s" % (
            self.srv, self.sub, self.plan, self.group, self.subgroup,
            self.defrate, self.altrate )

def setRates( obj, aSearch ):
    for rate in aSearch:
        if rate.text.strip() == "default":
            obj.defrate= rate.find("rate").text.strip()
        elif rate.text.strip() == "alternative":
            obj.altrate= rate.find("rate").text.strip()
        else:
            raise Exception( "Unexpected Structure" )

def planIter( doc ):
    for topNode in doc.findall( "node" ):
        obj= Plan()
        obj.srv= topNode.text.strip()
        subNode= topNode.find("node")
        obj.sub= subNode.text.strip()
        planNode= topNode.find("node/node")
        obj.plan= planNode.text.strip()
        l3= topNode.find("node/node/node")
        if l3.text.strip() in ( "default", "alternative" ):
            setRates( obj, topNode.findall("node/node/node") )
            yield obj
        else:
            for group in topNode.findall("node/node/node"):
                grpObj= Plan()
                grpObj.initFrom( obj )
                grpObj.group= group.text.strip()
                l4= group.find( "node" )
                if l4.text.strip() in ( "default", "alternative" ):
                    setRates( grpObj, group.findall( "node" ) )
                    yield grpObj
                else:
                    for subgroup in group.findall("node"):
                        subgrpObj= Plan()
                        subgrpObj.initFrom( grpObj )
                        subgrpObj.subgroup= subgroup.text.strip()
                        setRates( subgrpObj, subgroup.findall("node") )
                        yield subgrpObj

import xml.etree.ElementTree as xml
doc = xml.XML( doc )

for plan in planIter( doc ):
    print plan

Редактировать

Тот, кто дал вам этот документ XML, должен найти другую работу. Это плохая вещь (TM) и указывает на довольно случайное игнорирование того, что означает XML.

0 голосов
/ 27 марта 2009

Я не слишком знаком с модулем ElementTree, но вы должны быть в состоянии использовать метод getchildren() для элемента и рекурсивно анализировать данные, пока не останется дочерних элементов. Это больше sudo-кода, чем что-либо:

def parseXml(root, data):
    # INSERT CODE to populate your data object here with the values 
    # you want from this node
    sub_nodes = root.getchildren()
    for node in sub_nodes:
        parseXml(node, data)

data = {}  # I'm guessing you want a dict of some sort here to store the data you parse
parseXml(parse(file).getroot(), data)
# data will be filled and ready to use
...