2

我正在尝试解析一个 xml 文件并将其排列到一个表格中,将内容分隔为 isElement、isAttribute、Value、Text。

如何使用 ElementTree 模块来实现这一点?我知道使用 minidom 模块可以做到这一点。

我想使用 ElementTree 的原因是效率。此处提供了我想要实现的示例:http: //python.zirael.org/e-gtk-treeview4.html

关于如何使用 ElementTree 模块将 xml 内容分离为元素、子元素等的任何建议?

这是我到目前为止所拥有的:

import xml.etree.cElementTree as ET

filetree = ET.ElementTree(file = "some_file.xml")
for child in filetree.iter():
     print child.tag, child.text, child.attrib

对于以下示例 xml 文件:

    <?xml version="1.0"?>
    <data>
        <country name="Liechtenstein">
            <rank>1</rank>
            <year>2008</year>
            <gdppc>141100</gdppc>
            <neighbor name="Austria" direction="E"/>
            <neighbor name="Switzerland" direction="W"/>
        </country>
        <country name="Singapore">
            <rank>4</rank>
            <year>2011</year>
            <gdppc>59900</gdppc>
            <neighbor name="Malaysia" direction="N"/>
        </country>
        <country name="Panama">
            <rank>68</rank>
            <year>2011</year>
            <gdppc>13600</gdppc>
            <neighbor name="Costa Rica" direction="W"/>
            <neighbor name="Colombia" direction="E"/>
        </country>
    </data>

我得到这个作为输出:

    data 
         {}
    country 
             {'name': 'Liechtenstein'}
    rank 1 {}
    year 2008 {}
    gdppc 141100 {}
    neighbor None {'direction': 'E', 'name': 'Austria'}
    neighbor None {'direction': 'W', 'name': 'Switzerland'}
    country 
             {'name': 'Singapore'}
    rank 4 {}
    year 2011 {}
    gdppc 59900 {}
    neighbor None {'direction': 'N', 'name': 'Malaysia'}
    country 
             {'name': 'Panama'}
    rank 68 {}
    year 2011 {}
    gdppc 13600 {}
    neighbor None {'direction': 'W', 'name': 'Costa Rica'}
    neighbor None {'direction': 'E', 'name': 'Colombia'}

我确实在另一篇文章中找到了类似的东西,但它使用了 DOM 模块。 遍历元素嵌套结构中的所有 XML 节点

根据收到的评论,这就是我想要实现的目标:

    data (type Element)
         country(Element)
              Text = None
              name(Attribute)
                 value: Liechtenstein
              rank(Element)
                  Text = 1
              year(Element)
                  Text = 2008
              gdppc(Element)
                  Text = 141100
              neighbour(Element)
                  name(Attribute)
                      value: Austria
                  direction(Attribute)
                      value: E
              neighbour(Element)
                  name(Attribute)
                      value: Switzerland
                  direction(Attribute)
                      value: W

         country(Element)
              Text = None
              name(Attribute)
                 value: Singapore
              rank(Element)
                  Text = 4

我希望能够以上述树状结构呈现我的数据。为此,我需要跟踪他们的关系。希望这能澄清这个问题。

4

2 回答 2

1

Element对象是包含其直接子元素的序列。XML 属性存储在将属性名称映射到值的字典中。DOM 中没有文本节点。文本存储为texttail属性。元素内但第一个子元素之前的text文本存储在 中,该元素与下一个元素之间的文本存储在tail. 因此,如果我们以TreeView IV中的gtk-treeview4-2.py为例。- 显示树我们必须重写这个 DOM 代码:

# ...
import xml.dom.minidom as dom
# ...

    def create_interior(self):
        # ...
        doc = dom.parse(self.filename)
        self.add_element_to_treestore(doc.childNodes[0], None)
        # ...

    def add_element_to_treestore(self, e, parent):
        if isinstance(e, dom.Element):
            me = self.model.append(parent, [e.nodeName, 'ELEMENT', ''])
            for i in range(e.attributes.length):
                a = e.attributes.item(i)
                self.model.append(me, ['@' + a.name, 'ATTRIBUTE', a.value])
            for ch in e.childNodes:
                self.add_element_to_treestore(ch, me)
        elif isinstance(e, dom.Text):
            self.model.append(
                parent, ['text()', 'TEXT_NODE', e.nodeValue.strip()])

通过以下使用ElementTree

# ...
from xml.etree import ElementTree as etree
# ...

    def create_interior(self):
        # ...
        doc = etree.parse(self.filename)
        self.add_element_to_treestore(doc.getroot())
        # ...

    def add_element_to_treestore(self, element, parent=None):
        path = self.model.append(parent, [element.tag, 'ELEMENT', ''])
        for name, value in sorted(element.attrib.iteritems()):
            self.model.append(path, ['@' + name, 'ATTRIBUTE', value])
        if element.text:
            self.model.append(
                path, ['text()', 'TEXT_NODE', element.text.strip()]
            )
        for child in element:
            self.add_element_to_treestore(child, path)
            if element.tail:
                self.model.append(
                    path, ['text()', 'TEXT_NODE', element.tail.strip()]
                )

您的示例数据和第一个子树完全展开的屏幕截图:

示例数据的屏幕截图


更新:添加了示例数据的屏幕截图和代码中的相关导入行。

于 2015-09-05T21:20:01.023 回答
0

可能不完全是您需要的,但您可以使用 XSLT 转换 XML 以实现树状结构:

XSLT(包括制表符和换行符)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8"/>

<xsl:template match="data">

<xsl:variable name="tabonce"><xsl:text>&#10;&#x9;</xsl:text></xsl:variable>
<xsl:variable name="tabtwice"><xsl:text>&#10;&#x9;&#x9;</xsl:text></xsl:variable>

<data>
    data (type Element)<xsl:text>&#10;&#x9;</xsl:text>
    <xsl:for-each select="country">
           <xsl:value-of select="concat(local-name(.), '(Element)')"/>
           Text = <xsl:value-of select="concat('None', $tabonce)"/> 
           <xsl:value-of select="concat(name(@*), '(Attribute)')"/>
              value: <xsl:value-of select="concat(@*, $tabonce)"/>          

        <xsl:for-each select="*">
        <xsl:value-of select="concat(local-name(.), '(Element)')"/>     
              Text = <xsl:value-of select="concat(., $tabonce)"/> 

              <xsl:if test="@*">
                 <xsl:text>&#x9;</xsl:text><xsl:value-of select="concat(name(@name), '(Attribute)')"/>
                 value: <xsl:value-of select="concat(@name, $tabtwice)"/>  
                 <xsl:value-of select="concat(name(@direction), '(Attribute)')"/>
                 value: <xsl:value-of select="concat(@direction, $tabonce)"/> 
              </xsl:if>

        </xsl:for-each>
        <xsl:text>&#10;&#x9;</xsl:text>

    </xsl:for-each>
    <xsl:text>&#10;</xsl:text>
</data>    

</xsl:template>
</xsl:stylesheet>

使用 lxml 模块的 Python 脚本:

import lxml.etree as ET

dom = ET.parse('C:\Path\To\XMLfile.xml')
xslt = ET.parse('C:\Path\To\XSLfile.xsl')
transform = ET.XSLT(xslt)
newdom = transform(dom)

tree_out = ET.tostring(newdom, encoding='UTF-8', pretty_print=True,  xml_declaration=True)
print(tree_out)

xmlfile = open('C:\Path\To\OutputPath.xml','wb')
xmlfile.write(tree_out)
xmlfile.close()

XML 输出

<?xml version='1.0' encoding='UTF-8'?>
<data>
    data (type Element)
    country(Element)
        Text = None
    name(Attribute)
        value: Liechtenstein
    rank(Element)       
        Text = 1
    year(Element)       
        Text = 2008
    gdppc(Element)      
        Text = 141100
    neighbor(Element)       
        Text = 
        name(Attribute)
            value: Austria
        direction(Attribute)
            value: E
    neighbor(Element)       
        Text = 
        name(Attribute)
            value: Switzerland
        direction(Attribute)
            value: W

    country(Element)
        Text = None
    name(Attribute)
        value: Singapore
    rank(Element)       
        Text = 4
    year(Element)       
        Text = 2011
    gdppc(Element)      
        Text = 59900
    neighbor(Element)       
        Text = 
        name(Attribute)
            value: Malaysia
        direction(Attribute)
            value: N

    country(Element)
        Text = None
    name(Attribute)
        value: Panama
    rank(Element)       
        Text = 68
    year(Element)       
        Text = 2011
    gdppc(Element)      
        Text = 13600
    neighbor(Element)       
        Text = 
        name(Attribute)
            value: Costa Rica
        direction(Attribute)
            value: W
    neighbor(Element)       
        Text = 
        name(Attribute)
            value: Colombia
        direction(Attribute)
            value: E


</data>
于 2015-09-07T17:17:47.417 回答