如何找到嵌套在两个不同标签中的两个同名节点的位置?

时间:2011-05-12 11:29:28

标签: java xml xslt xpath

我有以下XML:

<employees>
   <employee>   <!--forgot to include an attribute-->
      <name>John</name>
      <jobs>
          <job>Writer</job>
          <job>Artist</job>
     </jobs>
   </employee>
   <employee>
      <name>John</name>
      <jobs>
          <job>Engineer</job>
          <job>Editor</job>
     </jobs>
   </employee>
</employees>

如果我想获得姓名为“John”的人的工作,XPath将返回属于一个“John”的所有四个工作。我希望由两个不同的“约翰”各自完成2 + 2个不同的工作。

我使用XPath表达式

"//employees/employee[name='John']/jobs/job/text()"

在java中使用count或其他函数的XPath中有没有办法做到这一点?

2 个答案:

答案 0 :(得分:2)

XPath是(仅)XML文档的查询语言 - 评估结果XPath表达式永远不是修改过的节点 - 仅XPath不会改变结构和/或内容任何节点。

您想要返回的内容是修改后的<employee>元素,仅包含<jobs>子元素,而单凭XPath无法实现这一点。

最接近您想要的是

/*/employee[name='John']/jobs

选择以下

    <jobs>
        <job>Writer</job>
        <job>Artist</job>
    </jobs>
    <jobs>
        <job>Engineer</job>
        <job>Editor</job>
    </jobs>

我猜想通过此XSLT转换可以非常轻松地生成您想要的结果

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

 <xsl:template match="/">
     <xsl:copy-of select=
     "/*/employee[name='John']/node()[not(self::comment())]"/>
 </xsl:template>
 </xsl:stylesheet>

将此转换应用于提供的XML文档

<employees>
    <employee>
        <!--forgot to include an attribute-->
        <name>John</name>
        <jobs>
            <job>Writer</job>
            <job>Artist</job>
        </jobs>
    </employee>
    <employee>
        <name>John</name>
        <jobs>
            <job>Engineer</job>
            <job>Editor</job>
        </jobs>
    </employee>
</employees>

产生了想要的正确结果

<name>John</name>
<jobs>
   <job>Writer</job>
   <job>Artist</job>
</jobs>
<name>John</name>
<jobs>
   <job>Engineer</job>
   <job>Editor</job>
</jobs>

答案 1 :(得分:0)

XPath始终会返回一个平面列表,无论找到哪个节点,这就是为什么你只需要获得4个文本。如果要按父节点对它们进行分组,则需要首先搜索Johns并使用这些结果,对每个John执行嵌套循环,从该节点开始为作业执行XPath。您希望如何使用Java对它们进行分组取决于您 - 可能是字符串(名称)到字符串列表(作业)。