XML-XSL-仅选择符合条件的第一个元素

时间:2019-02-19 15:50:45

标签: xml xslt xpath xslt-1.0 xpath-1.0

假设,我确实有一个 MyObject 元素数组,该数组具有一些属性,例如 IsFinalResult ,我想根据此属性有选择地选择项目。 我希望该逻辑仅从数组中获取 first 元素,该元素匹配给定条件 IsFinalResult == true (即使乘法元素匹配条件)。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="/">
      <xsl:for-each select="ArrayOfMyObject/MyObject">
         <xsl:choose>
            <xsl:when test="// Here how to check?">
               // this will match only once
            </xsl:when>
            <xsl:otherwise>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:for-each>
   </xsl:template>
</xsl:stylesheet>

我只能使用XPath 1.0来做到这一点。

2 个答案:

答案 0 :(得分:1)

您可以使用position()函数

<xsl:when test="position() = 1 and IsFinalResult='true'">
   // this will match only once
</xsl:when>

但是还有其他方法可以处理这种情况。
其中之一是对谓词使用模板匹配:

<xsl:template match="/ArrayOfMyObject/MyObject[IsFinalResult = 'true' and position() = 1]">
  <!-- For the first MyObject element -->
  ...

<xsl:template match="/ArrayOfMyObject/MyObject[IsFinalResult = 'true' and position() > 1]">
  <!-- For all the other MyObject elements -->
  ...

受以下评论的启发,还有另一种方式来阅读您的问题(我在此答案的先前版本中曾有过)。这种方式可以通过使用两个单独的条件来实现:

<xsl:for-each select="ArrayOfMyObject/MyObject[IsFinalResult='true']">
  <xsl:choose>
    <xsl:when test="position() = 1">
      // this will match only once
    </xsl:when>
  ...

第二种方式更改如下:

<xsl:template match="/ArrayOfMyObject/MyObject[IsFinalResult = 'true'][1]">
  <!-- Matches the first element of the list of elements that satisfy the first predicate -->
  ...

这里[1]不是必需的-考虑将其视为强调可读性的一种方法。
还有

<xsl:template match="/ArrayOfMyObject/MyObject[IsFinalResult = 'true'][position() > 1]">
  <!-- Matches all the other elements of the list of elements that satisfy the first predicate -->
  ...

答案 1 :(得分:0)

考虑使用模板方法...

<xsl:template match="/">
  <xsl:apply-templates select="ArrayOfMyObject/MyObject" />
</xsl:template>

然后,为了表示您的xsl:when测试,以匹配第一个“ IsFinalResult ='true'”元素,则模板匹配应为以下内容……

<xsl:template match="MyObject[@IsFinalResult='true'][1]">

(注意,我假设IsFinalResult是此处的属性。如果不是,只需删除@前缀)

要代表您的xsl:otherwise,请使用一个模板(优先级较低),该模板将提取所有其他MyObject元素

<xsl:template match="MyObject">

因此,鉴于以下XML:

<ArrayOfMyObject>
    <MyObject IsFinalResult="false">1</MyObject>
    <MyObject IsFinalResult="false">2</MyObject>
    <MyObject IsFinalResult="true">3</MyObject>
    <MyObject IsFinalResult="false">4</MyObject>
    <MyObject IsFinalResult="true">5</MyObject>
    <MyObject IsFinalResult="true">6</MyObject>
</ArrayOfMyObject>

如果您应用此XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <xsl:apply-templates select="ArrayOfMyObject/MyObject" />
  </xsl:template>

  <xsl:template match="MyObject[@IsFinalResult='true'][1]">
    <When>
      <xsl:value-of select="." />
    </When>
  </xsl:template>

  <xsl:template match="MyObject">
    <Otherwise>
      <xsl:value-of select="." />
    </Otherwise>
  </xsl:template>
</xsl:stylesheet>

输出是这个...

<Otherwise>1</Otherwise>
<Otherwise>2</Otherwise>
<When>3</When>
<Otherwise>4</Otherwise>
<Otherwise>5</Otherwise>
<Otherwise>6</Otherwise>

(如果仅考虑将<xsl:template match="MyObject[@IsFinalResult='true' and position() = 1]">作为模板的第一个子元素,则将模板匹配项更改为@IsFinalResult='true'

请注意,如果只希望xsl:otherwise处理IsFinalResult="true"(在第一个之后)中的元素,则只需添加第三个模板即可忽略其他元素

<xsl:template match="MyObject[not(@IsFinalResult='true')]" />