在xpath谓词中使用distinct-values

时间:2018-04-02 16:47:23

标签: xml xpath xslt-2.0

我正在使用XSLT / Xpath 2.0,我正在尝试编写一个xpath语句,这将允许我过滤我在XML中的一些重复的节点集。这是一个XML示例:

<?xml version="1.0" encoding="utf-8"?>
<test>
    <card>
        <TimeCard>1234</TimeCard>
        <tax>HST</tax>
        <adjAmt>-112</adjAmt>
    </card>
    <card>
        <TimeCard>1234</TimeCard>
        <tax>GST</tax>
        <adjAmt>-112</adjAmt>
    </card>
    <card>
        <TimeCard>4321</TimeCard>
        <tax>HST</tax>
        <adjAmt>-50</adjAmt>
    </card>
    <card>
        <TimeCard>4321</TimeCard>
        <tax>GST</tax>
        <adjAmt>-50</adjAmt>
    </card>
    <card>
        <TimeCard>2121</TimeCard>
        <tax>GST</tax>
        <adjAmt>-55</adjAmt>
    </card>
</test>

我需要一个返回“adjAmt”的xpath,但每个“TimeCard”只返回一次。当收取不同类型的税款时,我的主机系统为“adjAmt”创建重复的“卡”条目。在上面的例子中,我只有一个它返回-112,-50和-55;每个“时间卡”一个条目。

我尝试在时间卡元素的众多不同位置使用不同的值,但没有任何运气。

任何人对什么可能效果最好都有任何建议?

2 个答案:

答案 0 :(得分:0)

使用

来自

distinct-values()

$ saxon-lint --xpath '
   for $x in distinct-values(/test/card/TimeCard/text())
      return (/test/card/TimeCard[text()=$x]/following-sibling::adjAmt/text())[1]
' file.xml

$ xidel -se '
   for $x in distinct-values(/test/card/TimeCard/text())
      return (/test/card/TimeCard[text()=$x]/following-sibling::adjAmt/text())[1]
' file.xml
来自

group by

$ saxon-lint --no-pi --xquery '
  for $card in test/card group by $tcard := $card/TimeCard
     return $card[1]/adjAmt/data()
' file.xml

$ xidel -s --xquery '
  for $card in test/card group by $tcard := $card/TimeCard
     return $card[1]/adjAmt/data()
' file.xml

感谢Martin Honnen最后一次查询

检查saxon wrapper   我自己的项目

答案 1 :(得分:0)

在XSLT 2或3中,您可以使用for-each-group group-bycard子元素对TimeCard元素进行分组,然后返回上下文节点的adjAmt子元素或其数值如下:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf"
    version="3.0">

  <xsl:output method="text"/>

  <xsl:function name="mf:group-and-select-first" as="xs:decimal*">
      <xsl:param name="cards" as="element(card)*"/>
      <xsl:for-each-group select="$cards" group-by="TimeCard">
          <xsl:sequence select="xs:decimal(adjAmt)"/>
      </xsl:for-each-group>
  </xsl:function>

  <xsl:template match="/">
     <xsl:value-of select="mf:group-and-select-first(test/card)"/>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bFDb2BP

我已将该分组代码包装到函数中,因为您的问题涉及在XPath谓词中使用代码,该示例只是在xsl:value-of select表达式的函数调用中调用该函数,但当然您也可以如果需要,在谓词中使用该函数。