Python XML - создание плоской записи из динамических вложенных элементов «узла»

1

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

Я лучше всего знаком с python ElementTree, поэтому я бы предпочел использовать его, но я просто не могу обернуть голову, чтобы динамически строить выходную запись на основе динамической глубины node. Кроме того, мы не можем предположить, что вложенные узлы будут x уровнями глубокими, поэтому просто hardcoding каждый уровень w/loop невозможен. Есть ли способ разобрать XML и построить вывод на лету?

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

  • Имена node - это все "node" , кроме информации о родителях и деталях (скорость, цена и т.д.).
  • Глубина node не является статичной. Итак - предположим дополнительные уровни, чем отображаемые в образце
  • Каждый "уровень" может иметь несколько подуровней. Итак - вам нужно петлировать каждый дочерний элемент "node" для правильной сборки каждой записи.

Приветствуются любые идеи/ввод.

<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
Теги:
elementtree

2 ответа

4

Вот почему у вас есть метод Element Tree 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

Edit

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

  • 0
    Спасибо за быстрый ответ. Все имена узлов являются «узлами», и, к сожалению, как я уже говорил ранее, я не могу предположить, что «подгруппа» является последним уровнем, иначе это было бы очень легко. Глубина узла не является статической. Там могут быть дети подгруппы "узел". Мысли? Еще раз спасибо!
  • 0
    Также - каждый «уровень» может иметь несколько подуровней. Таким образом, создание одного объекта только из цикла верхнего узла не будет работать. Вам также нужно создать цикл на каждом дочернем «узле», чтобы построить каждую запись.
Показать ещё 4 комментария
0

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню