获取属性的XPath

huangapple go评论79阅读模式
英文:

Get XPath to attribute

问题

我想获取特定xml元素树中特定属性的实际XPath表达式,使用lxml。

假设以下XML树。

XPath表达式"//@*[local-name() = "attrib_name"]"会产生['hello_world'],这是相关属性的值,而"//@*[local-name() = "attrib_name"]/.."会得到bar元素,这一层级太高了,我需要xpath表达式指向特定的属性节点本身,而不是它的父xml节点,我想生成的是'/foo/bar/@attrib_name'。

from lxml import etree
from io import StringIO

f = StringIO('<foo><bar attrib_name="hello_world"></bar></foo>')
tree = etree.parse(f)

print(tree.xpath('//@*[local-name() = "attrib_name"]'))
# --> ['hello_world']
print([tree.getpath(el) for el in tree.xpath('//@*[local-name() = "attrib_name"]/..')])
# --> ['/foo/bar']

作为附加功能,这也适用于命名空间。

英文:

I want to get the actual XPath expression to an attribute node for a specific attribute in an xml element tree (using lxml).

Suppose the following XML tree.

<foo>
  <bar attrib_name="hello_world"/>
</foo>

The XPath expression "//@*[local-name() = "attrib_name"]" produces ['hello_world'] which is the values of concerned attributes, and "//@*[local-name() = "attrib_name"]/.." gets me the bar element, which is one level too high, I need the xpath expression to the specific attribute node itself, not its parent xml node, that is having the string 'attrib_name' I want to generate '/foo/bar/@attrib_name'.

from lxml import etree
from io import StringIO

f = StringIO('<foo><bar attrib_name="hello_world"></bar></foo>')
tree = etree.parse(f)

print(tree.xpath('//@*[local-name() = "attrib_name"]'))
# --> ['hello_world']
print([tree.getpath(el) for el in tree.xpath('//@*[local-name() = "attrib_name"]/..')])
# --> ['/foo/bar']

As an add-on this should work with namespaces too.

答案1

得分: 2

如果您移除 /..,然后您将获得 _ElementUnicodeResult

这将允许您将属性名称附加到 xpath:

>>> print(['%s/@%s' % (tree.getpath(attrib_result.getparent()), attrib_result.attrname) for attrib_result in tree.xpath('//@*[local-name() = "attrib_name"]')])
['/foo/bar/@attrib_name']

尝试将其应用于命名空间将导致命名空间添加到 xpath(这可能不是您想要的):

>>> tree = etree.parse(StringIO('<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><bar xsi:attrib_name="hello_world"></bar></foo>'))
>>> print(['%s/@%s' % (tree.getpath(attrib_result.getparent()), attrib_result.attrname) for attrib_result in tree.xpath('//@*[local-name() = "attrib_name"]')])
['/foo/bar/@{http://www.w3.org/2001/XMLSchema-instance}attrib_name']
英文:

If you remove the /.. then you will get the _ElementUnicodeResult

This will allow you to append the attribute name to the xpath:

>>> print(['%s/@%s' % (tree.getpath(attrib_result.getparent()), attrib_result.attrname) for attrib_result in tree.xpath('//@*[local-name() = "attrib_name"]')])
['/foo/bar/@attrib_name']

Trying to apply that to namespaces will result in the namespace added to the xpath (which may not be what you want):

>>> tree = etree.parse(StringIO('<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><bar xsi:attrib_name="hello_world"></bar></foo>'))
>>> print(['%s/@%s' % (tree.getpath(attrib_result.getparent()), attrib_result.attrname) for attrib_result in tree.xpath('//@*[local-name() = "attrib_name"]')])
['/foo/bar/@{http://www.w3.org/2001/XMLSchema-instance}attrib_name']

huangapple
  • 本文由 发表于 2020年1月6日 23:12:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/59614516.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定