【问题标题】:Python XML - build flat record from dynamic nested "node" elementsPython XML - 从动态嵌套的“节点”元素构建平面记录
【发布时间】:2009-03-27 11:09:06
【问题描述】:

我需要解析一个 XML 文件并从数据中构建一个基于记录的输出。问题在于 XML 是一种“通用”形式,因为它具有多个级别的嵌套“节点”元素,这些元素表示某种数据结构。我需要根据“节点”元素的最深层动态构建记录。一些示例 XML 和预期输出在底部。

我最熟悉 w/python 的 ElementTree,所以我更喜欢使用它,但我无法理解一种基于动态节点深度动态构建输出记录的方法。另外 - 我们不能假设嵌套节点的深度为 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

【问题讨论】:

    标签: python xml elementtree


    【解决方案1】:

    这就是为什么你有元素树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 文档的人需要另找一份工作。 This is A Bad Thing (TM) 表示对 XML 含义的相当随意的漠视。

    【讨论】:

    • 感谢您的快速回复。节点名称都是“节点”,不幸的是,正如我之前所说,我不能假设“子组”是最后一级,否则这将非常容易。节点深度不是静态的。可能有子组“节点”的孩子。想法?再次感谢!
    • 另外——每个“级别”可以有多个子级别。因此,仅从顶部节点循环创建单个对象是行不通的。您还需要在每个子“节点”上循环以构建每条记录。
    • @S.Lott - 我不能更同意 XML 结构,但不幸的是,它是“系统生成的”,他们拒绝更改它。 :-(
    • @John:他们无能。如果他们只是简单地对 DOM 对象进行子类化,那将是微不足道的。严重地。他们在做什么 在两个层面上都是坏事——这是错误的,他们拒绝改变。
    • @S.Lott - 哈!再一次,不能同意更多。当我解释糟糕的 XML 结构和改变的必要性时,他们只是用空白的脸看着我说“那不能改变”。哦,好吧——没有什么比构建一个复杂的解决方案来处理糟糕的设计更重要的了。再次感谢。
    【解决方案2】:

    我对@9​​87654321@ 模块不太熟悉,但是您应该能够在元素上使用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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多