ElementTree 模块分隔 xml 内容
ElementTree module to separate xml contents
我正在尝试解析 xml 文件并将其排列成 table 将内容分隔为 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'}
我确实在另一个 post 上找到了类似的东西,但它使用了 DOM 模块。
Walk through all XML nodes in an element-nested structure
根据收到的评论,这是我想要实现的目标:
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
我希望能够在树状结构中呈现我的数据,如上所示。为此,我需要跟踪他们的关系。希望这可以澄清问题。
Element
对象是包含其直接子元素的序列。 XML 属性存储在将属性名称映射到值的字典中。 DOM 中没有文本节点。文本存储为 text
和 tail
属性。元素内但在第一个子元素之前的文本存储在 text
中,该元素与下一个子元素之间的文本存储在 tail
中。因此,如果我们采用 TreeView IV. - display of trees 中的 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()]
)
您的示例数据和第一个子树完全展开的屏幕截图:
更新: 添加了代码中示例数据和相关导入行的屏幕截图。
可能不完全是您需要的,但您可以使用 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> 	</xsl:text></xsl:variable>
<xsl:variable name="tabtwice"><xsl:text> 		</xsl:text></xsl:variable>
<data>
data (type Element)<xsl:text> 	</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>	</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> 	</xsl:text>
</xsl:for-each>
<xsl:text> </xsl:text>
</data>
</xsl:template>
</xsl:stylesheet>
Python 使用 lxml 模块的脚本:
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>
我正在尝试解析 xml 文件并将其排列成 table 将内容分隔为 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'}
我确实在另一个 post 上找到了类似的东西,但它使用了 DOM 模块。 Walk through all XML nodes in an element-nested structure
根据收到的评论,这是我想要实现的目标:
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
我希望能够在树状结构中呈现我的数据,如上所示。为此,我需要跟踪他们的关系。希望这可以澄清问题。
Element
对象是包含其直接子元素的序列。 XML 属性存储在将属性名称映射到值的字典中。 DOM 中没有文本节点。文本存储为 text
和 tail
属性。元素内但在第一个子元素之前的文本存储在 text
中,该元素与下一个子元素之间的文本存储在 tail
中。因此,如果我们采用 TreeView IV. - display of trees 中的 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()]
)
您的示例数据和第一个子树完全展开的屏幕截图:
更新: 添加了代码中示例数据和相关导入行的屏幕截图。
可能不完全是您需要的,但您可以使用 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> 	</xsl:text></xsl:variable>
<xsl:variable name="tabtwice"><xsl:text> 		</xsl:text></xsl:variable>
<data>
data (type Element)<xsl:text> 	</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>	</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> 	</xsl:text>
</xsl:for-each>
<xsl:text> </xsl:text>
</data>
</xsl:template>
</xsl:stylesheet>
Python 使用 lxml 模块的脚本:
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>