访问下一个兄弟的文本

时间:2016-02-03 10:32:48

标签: python xml xpath jenkins elementtree

这是jenkins xml文件的一部分。

我想用xpath提取project_name的defaultValue。

我在这种情况下的值为*****

<?xml version='1.0' encoding='UTF-8'?>
<project>
    <properties>
        <hudson.model.ParametersDefinitionProperty>
            <parameterDefinitions>
                <hudson.model.StringParameterDefinition>
                    <name>customer_name</name>
                    <description></description>
                    <defaultValue>my_customer</defaultValue>
                </hudson.model.StringParameterDefinition>
                <hudson.model.StringParameterDefinition>
                    <name>project_name</name>
                    <description></description>
                    <defaultValue>*****</defaultValue>
                </hudson.model.StringParameterDefinition>
            </parameterDefinitions>
        </hudson.model.ParametersDefinitionProperty>
    </properties>
 </project>

我使用python的etree,但AFAIK这并不重要,因为这是一个xpath问题。

我目前的xpath知识有限。我目前的做法:

for name_tag in config.findall('.//name'):
    if name_tag.text=='project_host':
        default=name_tag.getparent().findall('defaultValue')[0].text

我在这里得到AttributeError: 'Element' object has no attribute 'getparent'

我再次想到这一点,我认为在python中循环是错误的方法。这应该可以通过xpath选择。

2 个答案:

答案 0 :(得分:2)

XPath对您问题的回答是

/project/properties/hudson.model.ParametersDefinitionProperty/parameterDefinitions/hudson.model.StringParameterDefinition[name = 'project_name']/defaultValue/text()

将选择唯一的结果

*****

鉴于您的实际文档没有命名空间。您不需要访问父元素也不需要访问兄弟轴。

甚至etree应该支持这种XPath表达式,但它可能不支持 - 请参阅comment by har07

  

我再次想到这一点,我认为在python中循环是错误的方法。这应该可以通过xpath选择。

是的,我同意。如果要从文档中选择单个值,请使用XPath表达式选择它并将其直接存储为Python字符串,而不循环遍历元素。

lxml的完整示例

from lxml import etree
from StringIO import StringIO

document_string = """<project>
    <properties>
        <hudson.model.ParametersDefinitionProperty>
            <parameterDefinitions>
                <hudson.model.StringParameterDefinition>
                    <name>customer_name</name>
                    <description></description>
                    <defaultValue>my_customer</defaultValue>
                </hudson.model.StringParameterDefinition>
                <hudson.model.StringParameterDefinition>
                    <name>project_name</name>
                    <description></description>
                    <defaultValue>*****</defaultValue>
                </hudson.model.StringParameterDefinition>
            </parameterDefinitions>
        </hudson.model.ParametersDefinitionProperty>
    </properties>
 </project>"""

tree = etree.parse(StringIO(document_string))

result_list = tree.xpath("/project/properties/hudson.model.ParametersDefinitionProperty/parameterDefinitions/hudson.model.StringParameterDefinition[name = 'project_name']/defaultValue/text()")

print result_list[0]

输出:

*****

答案 1 :(得分:1)

您可以尝试lxml.etree,如下所示 - 我使用循环来选择具有相同位置的所有节点。

所需的xpath的示例是 - 我使用了relative xpath,因为它非常有用,包含长节点路径。

.//hudson.model.StringParameterDefinition/name[contains(text(),'project_name')]/following-sibling::defaultValue

OR

.//hudson.model.StringParameterDefinition/name[contains(text(),'project_name')]/following::defaultValue[1]
from lxml import etree as et

data  = """<?xml version='1.0' encoding='UTF-8'?>
<project>
    <properties>
        <hudson.model.ParametersDefinitionProperty>
            <parameterDefinitions>
                <hudson.model.StringParameterDefinition>
                    <name>customer_name</name>
                    <description></description>
                    <defaultValue>my_customer</defaultValue>
                </hudson.model.StringParameterDefinition>
                <hudson.model.StringParameterDefinition>
                    <name>project_name</name>
                    <description></description>
                    <defaultValue>*****</defaultValue>
                </hudson.model.StringParameterDefinition>
            </parameterDefinitions>
        </hudson.model.ParametersDefinitionProperty>
    </properties>
 </project>"""

tree = et.fromstring(data)

print [i.text for i in tree.xpath(".//hudson.model.StringParameterDefinition/defaultValue")]
print [i.text for i in tree.xpath(".//hudson.model.StringParameterDefinition/name[contains(text(),'project_name')]/following-sibling::defaultValue")]
print [i.text for i in tree.xpath(".//hudson.model.StringParameterDefinition/name[contains(text(),'project_name')]/following::defaultValue[1]")]

输出 -

['my_customer', '*****']
['*****']
['*****']