如何根据多个子节点值获取父节点?

时间:2011-08-26 16:32:59

标签: xml xpath

<parents>
 <parent>
    <item>
        <name>200</name>
    </item>
    <item>
        <name>201</name>
    </item>
    <item>
        <name>204</name>
    </item>
 </parent>
 <parent>
     <item>
        <name>203</name>
     </item>
 </parent>
</parents>

我需要第一个parent节点,因为我有一个与项目对应的ID列表。考虑一下:

list = ['200', '201'];

因为在第一个200节点中找到parent,所以我想要parent个节点。如果200不存在,我仍会获得父节点,因为201是第一个/name/text()parent的值。

我唯一的要求是,如果找到parentone的{​​{1}}个ID,我就需要抓取list节点。

目前我只测试第一个,如下:

//name/child::text()[.="' . $firstKey . '"]/../../../../

$firstKey是对列表中第一个元素的引用,200。这并不理想,因为它不检查所有值,而只检查第一个值。

3 个答案:

答案 0 :(得分:1)

<强>予。使用XSLT 1.0作为主机的XPath 1.0解决方案:

使用:

/*/parent[item/name = $vList]

此转化

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:list>
  <val>200</val>
  <val>201</val>
 </my:list>

 <xsl:variable name="vList" select=
     "document('')/*/my:list/*"/>

 <xsl:template match="/">
     <xsl:copy-of select="*/parent[item/name = $vList]"/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<parents>
    <parent>
        <item>
            <name>200</name>
        </item>
        <item>
            <name>201</name>
        </item>
        <item>
            <name>204</name>
        </item>
    </parent>
    <parent>
        <item>
            <name>203</name>
        </item>
    </parent>
</parents>

生成想要的正确结果

<parent>
   <item>
      <name>200</name>
   </item>
   <item>
      <name>201</name>
   </item>
   <item>
      <name>204</name>
   </item>
</parent>

注意:您可以将现在<my:list>作为参数传递给转化。

<强> II。使用XPath 2.0 :

/*/parent[item/name = ('200', '201')]

基于XSLT 2.0的验证低于“

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
     <xsl:copy-of select="*/parent[item/name = ('200', '201')]"/>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档(上面)上应用此转换时,会产生相同的正确结果。

答案 1 :(得分:0)

这样的事情可能有所帮助:

//parent[.//item[name[text()='200' or text()='201']]]

但是,您必须以编程方式构造最内层谓词(使用text()='200' or ...)。我不确定你在哪个上下文中使用它,但是由于你使用的是变量引用,我假设是XSLT。我会看看是否有更合适的东西......

编辑:我唯一能想到的就是将所有密钥与某些符号连接在一起,您确定它们永远不会包含在分隔符中。例如:

200#201#...

然后使用XPath contains函数:

//parent[.//item[name[contains('200#201#...', normalize-space(text()))]]]

contains的第一个参数必须是你的连接键,可能作为变量传入。函数string-join对此有好处,但我相信它只适用于XPath 2.0。

答案 2 :(得分:0)

如果你有XSLT 2.0,你可以说

<xsl:variable name="list" select="(200, 201)" />
<xsl:variable name="theParent" select="(//parent[item/name = $list])[1]" />

=作为存在比较,如果左侧节点集中的任何项目等于=右侧序列中的任何项目,则返回true。

(未测试)。