使用 lxml 和 elementtree 解析 XML
Parsing XML with lxml and elementtree
我正在尝试将 XML 文档解析为包含 ref
属性的 return <input>
节点。玩具示例有效,但文档本身 return 是一个空数组,而它应该显示匹配项。
玩具示例
import elementtree.ElementTree
from lxml import etree
tree = etree.XML('<body><input ref="blabla"><label>Cats</label></input><input ref="blabla"><label>Dogs</label></input><input ref="blabla"><label>Birds</label></input></body>')
# I can return the relevant input nodes with:
print len(tree.findall(".//input[@ref]"))
2
但由于某种原因无法使用以下(简化的)文件:
example.xml
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<h:head>
<h:title>A title</h:title>
</h:head>
<h:body>
<group ref="blabla">
<label>Group 1</label>
<input ref="blabla">
<label>Field 1</label>
</input>
</group>
</h:body>
</h:html>
脚本
import elementtree.ElementTree
from lxml import etree
with open ("example.xml", "r") as myfile:
xml = myfile.read()
tree = etree.XML(xml)
print len(tree.findall(".//input[@ref]"))
0
知道为什么会失败吗?如何解决?我认为这可能与 XML header 有关。非常感谢任何帮助。
我认为问题在于整个文档中的元素特别是命名空间,因此未命名空间的 .findall(".//input[@ref]"))
表达式与文档中的 input
元素不匹配,这实际上是一个命名空间 input
元素,在 http://www.w3.org/2002/xforms
命名空间中。
也许试试这个:
.findall(".//{http://www.w3.org/2002/xforms}input[@ref]")
更新 在我原来的回答之后,使用 xforms 命名空间而不是 xhtml 命名空间(如另一个答案中所述)。
从你的 xml 可以看出,非前缀元素的 xml-namespace 是 - "http://www.w3.org/2002/xforms"
,这是因为它被定义为 xmlns
在父元素 h:html
中没有任何前缀,只有前缀为 h:
的元素的命名空间为 "http://www.w3.org/1999/xhtml"
.
因此您还需要在查询中使用该命名空间。示例 -
root.findall(".//{http://www.w3.org/2002/xforms}input[@ref]")
Example/Demo -
>>> s = """<?xml version="1.0"?>
... <h:html xmlns="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
... <h:head>
... <h:title>A title</h:title>
... </h:head>
... <h:body>
... <group ref="blabla">
... <label>Group 1</label>
... <input ref="blabla">
... <label>Field 1</label>
... </input>
... </group>
... </h:body>
... </h:html>"""
>>> import xml.etree.ElementTree as ET
>>> root = ET.fromstring(s)
>>> root.findall(".//{http://www.w3.org/1999/xhtml}input[@ref]")
>>> root.findall(".//{http://www.w3.org/2002/xforms}input[@ref]")
[<Element '{http://www.w3.org/2002/xforms}input' at 0x02288EA0>]
我正在尝试将 XML 文档解析为包含 ref
属性的 return <input>
节点。玩具示例有效,但文档本身 return 是一个空数组,而它应该显示匹配项。
玩具示例
import elementtree.ElementTree
from lxml import etree
tree = etree.XML('<body><input ref="blabla"><label>Cats</label></input><input ref="blabla"><label>Dogs</label></input><input ref="blabla"><label>Birds</label></input></body>')
# I can return the relevant input nodes with:
print len(tree.findall(".//input[@ref]"))
2
但由于某种原因无法使用以下(简化的)文件:
example.xml
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<h:head>
<h:title>A title</h:title>
</h:head>
<h:body>
<group ref="blabla">
<label>Group 1</label>
<input ref="blabla">
<label>Field 1</label>
</input>
</group>
</h:body>
</h:html>
脚本
import elementtree.ElementTree
from lxml import etree
with open ("example.xml", "r") as myfile:
xml = myfile.read()
tree = etree.XML(xml)
print len(tree.findall(".//input[@ref]"))
0
知道为什么会失败吗?如何解决?我认为这可能与 XML header 有关。非常感谢任何帮助。
我认为问题在于整个文档中的元素特别是命名空间,因此未命名空间的 .findall(".//input[@ref]"))
表达式与文档中的 input
元素不匹配,这实际上是一个命名空间 input
元素,在 http://www.w3.org/2002/xforms
命名空间中。
也许试试这个:
.findall(".//{http://www.w3.org/2002/xforms}input[@ref]")
更新 在我原来的回答之后,使用 xforms 命名空间而不是 xhtml 命名空间(如另一个答案中所述)。
从你的 xml 可以看出,非前缀元素的 xml-namespace 是 - "http://www.w3.org/2002/xforms"
,这是因为它被定义为 xmlns
在父元素 h:html
中没有任何前缀,只有前缀为 h:
的元素的命名空间为 "http://www.w3.org/1999/xhtml"
.
因此您还需要在查询中使用该命名空间。示例 -
root.findall(".//{http://www.w3.org/2002/xforms}input[@ref]")
Example/Demo -
>>> s = """<?xml version="1.0"?>
... <h:html xmlns="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
... <h:head>
... <h:title>A title</h:title>
... </h:head>
... <h:body>
... <group ref="blabla">
... <label>Group 1</label>
... <input ref="blabla">
... <label>Field 1</label>
... </input>
... </group>
... </h:body>
... </h:html>"""
>>> import xml.etree.ElementTree as ET
>>> root = ET.fromstring(s)
>>> root.findall(".//{http://www.w3.org/1999/xhtml}input[@ref]")
>>> root.findall(".//{http://www.w3.org/2002/xforms}input[@ref]")
[<Element '{http://www.w3.org/2002/xforms}input' at 0x02288EA0>]