precingshibling如何在XPath和Python中工作?它似乎显示了错误的输出

2024-06-28 11:38:51 发布

您现在位置:Python中文网/ 问答频道 /正文

对于XML数据

<X>
 <Y1>ABC1</Y1>
 <Y2>ABC2</Y2>
 <Z>
   <T>
     <R1>ABC3</R1>
     <R2>ABC4</R2>
   </T>
   <T>
     <R1>ABC5</R1>
     <R2>ABC6</R2>
   </T>
 </Z>
 <Y1>ABC7</Y1>
 <Y2>ABC8</Y2>
 <Z>
   <T>
     <R1>ABC3</R1>
     <R2>ABC9</R2>
   </T>
   <T>
     <R1>ABC5</R1>
     <R2>ABC9</R2>
   </T>
 </Z>
</X>

我编写了一个示例python文件,如下所示。你知道吗

from lxml import etree
tree = etree.parse('test.xml')
for i in tree.xpath("//X/Z/T[R1='ABC3']/parent::*/preceding-sibling::*"):
    print(i.tag, " - ", i.text)

我期望输出像

Y1  -  ABC1
Y2  -  ABC2
Y1  -  ABC1
Y2  -  ABC2
Z  -  

Y1  -  ABC7
Y2  -  ABC8

但我收到了一个

Y1  -  ABC1
Y2  -  ABC2
Z  -  

Y1  -  ABC7
Y2  -  ABC8

它应该打印所有前面的同级。对于“R1=ABC3”的第一个匹配,应该打印Y1和Y2。对于“R1=ABC”的第二个匹配,它应该打印5个同级。总共要打印7个元素。 这里的错误是什么?你知道吗


Tags: 数据treexmletreer2r1y1y2
2条回答

XPath1.0有一个节点集的概念,其中每个/步骤根据节点标识消除重复项,因此您使用的单个XPath表达式不会给出包含同一节点的集两次,任何重复项都会被消除。你知道吗

在XPath2.0中,当然/步骤运算符仍然具有相同的重复消除语义,但是在XPath3.1中有一个更通用的序列概念,它使用for .. returnfor $p in //X/Z/T[R1='ABC3']/parent::* return $p/preceding-sibling::*)或!//X/Z/T[R1='ABC3']/parent::*!preceding-sibling::*),允许您包含重复项,请参见https://xqueryfiddle.liberty-development.net/eiZQFoV。你知道吗

在XPath1.0中,需要在宿主语言(例如Python)的循环中使用多个XPath求值,或者在Python中可以使用列表理解element_list = [el for parent in tree.xpath("//X/Z/T[R1='ABC3']/parent::*") for el in parent.xpath("preceding-sibling::*")] 。你知道吗

问题被标记为xslt,但您没有使用XSLT。使用以下样式表可以实现预期的输出:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>

<xsl:template match="/X">
    <xsl:for-each select="Z[T/R1='ABC3']">
        <xsl:for-each select="preceding-sibling::*">
            <xsl:value-of select="name()" />
            <xsl:text> - </xsl:text>
            <xsl:value-of select="text()" />
            <xsl:text>&#10;</xsl:text>
        </xsl:for-each>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

正如Martin Honnen在回答中所指出的,为了得到两个单独的列表,有必要分别处理每个匹配节点的前面的兄弟节点。你知道吗


还要注意您的表达式:

Z/T[R1='ABC3']/parent::* 

是不必要的复杂:很明显,匹配的T的父级必须是Z,因此您可以简单地编写:

Z[T/R1='ABC3']

相关问题 更多 >