fly*_*eep 19 python xml xpath lxml elementtree
因为我第二次遇到这个烦人的问题,我觉得这个问题会有所帮助.
有时候我必须从XML文档中获取Elements,但是这样做的方法很尴尬.
我想知道一个python库,它可以实现我想要的,一种优雅的方式来表示我的XPath,一种在前缀中自动注册命名空间的方法,或者在内置XML实现中的隐藏首选项,或者在lxml中完全删除命名空间.澄清之后,除非你已经知道我想要什么:)
实施例-doc的:
<root xmlns="http://really-long-namespace.uri"
xmlns:other="http://with-ambivalent.end/#">
<other:elem/>
</root>
Run Code Online (Sandbox Code Playgroud)
ElementTree API是唯一内置的(我知道)提供XPath查询.但它需要我使用"UNames".这看起来像这样:/{http://really-long-namespace.uri}root/{http://with-ambivalent.end/#}elem
如您所见,这些都非常冗长.我可以通过以下方式缩短它们:
default_ns = "http://really-long-namespace.uri"
other_ns = "http://with-ambivalent.end/#"
doc.find("/{{{0}}}root/{{{1}}}elem".format(default_ns, other_ns))
Run Code Online (Sandbox Code Playgroud)
但是,这是双方{{{丑陋}}}和脆弱的,因为http…end/#≅ http…end#≅ http…end/≅ http…end和我是谁知道哪个变种会用吗?
此外,lxml支持名称空间前缀,但它既不使用文档中的名称前缀,也不提供处理默认名称空间的自动方法.我仍然需要从每个命名空间中获取一个元素以从文档中检索它.命名空间属性不会保留,因此也无法自动从这些属性中检索它们.
有一种与命名空间无关的XPath查询方式,但它在内置实现中既详细又丑陋且不可用: /*[local-name() = 'root']/*[local-name() = 'elem']
我想找到一个库,选项或通用的XPath变形函数,通过输入以下内容来实现上述示例...
/root/elem/root/other:elem...加上可能是一些我确实想要使用文档前缀或剥离命名空间的语句.
进一步澄清:虽然我目前的用例很简单,但将来我将不得不使用更复杂的用例.
谢谢阅读!
用户samplebias将我的注意力引向了py-dom-xpath ; 正是我在寻找什么.我的实际代码现在看起来像这样:
#parse the document into a DOM tree
rdf_tree = xml.dom.minidom.parse("install.rdf")
#read the default namespace and prefix from the root node
context = xpath.XPathContext(rdf_tree)
name = context.findvalue("//em:id", rdf_tree)
version = context.findvalue("//em:version", rdf_tree)
#<Description/> inherits the default RDF namespace
resource_nodes = context.find("//Description/following-sibling::*", rdf_tree)
Run Code Online (Sandbox Code Playgroud)
与文档一致,简单,名称空间感知; 完善.
sam*_*ias 14
该*[local-name() = "elem"]语法应该工作,但更容易,你可以创建一个函数来简化部分或全部"通配符命名空间" XPath表达式的建设.
我在Ubuntu 10.04上使用python-lxml 2.2.4,下面的脚本适合我.您需要根据您希望为每个元素指定默认命名空间的方式自定义行为,并处理要折叠到表达式中的任何其他XPath语法:
import lxml.etree
def xpath_ns(tree, expr):
"Parse a simple expression and prepend namespace wildcards where unspecified."
qual = lambda n: n if not n or ':' in n else '*[local-name() = "%s"]' % n
expr = '/'.join(qual(n) for n in expr.split('/'))
nsmap = dict((k, v) for k, v in tree.nsmap.items() if k)
return tree.xpath(expr, namespaces=nsmap)
doc = '''<root xmlns="http://really-long-namespace.uri"
xmlns:other="http://with-ambivalent.end/#">
<other:elem/>
</root>'''
tree = lxml.etree.fromstring(doc)
print xpath_ns(tree, '/root')
print xpath_ns(tree, '/root/elem')
print xpath_ns(tree, '/root/other:elem')
Run Code Online (Sandbox Code Playgroud)
输出:
[<Element {http://really-long-namespace.uri}root at 23099f0>]
[<Element {http://with-ambivalent.end/#}elem at 2309a48>]
[<Element {http://with-ambivalent.end/#}elem at 2309a48>]
Run Code Online (Sandbox Code Playgroud)
更新:如果您发现需要解析XPath,可以查看像py-dom-xpath这样的项目,它是(大部分)XPath 1.0的纯Python实现.至少,这将让您了解解析XPath的复杂性.
| 归档时间: |
|
| 查看次数: |
19453 次 |
| 最近记录: |