XSLT 中的特定方案

Specific Scenario in XSLT

提问人:User_Earth_005 提问时间:6/8/2023 最后编辑:User_Earth_005 更新时间:6/8/2023 访问量:40

问:

我删除了上一篇文章以使其更清楚。

输入 XML

<Org>
  <Name>OrgName</Name>
  <Type>OrgType</Type>
  <Customer>OrgCust</Customer>
  <Product>
    <ProductData>
      <ID>ID1</ID>
      <Name>Prod1</Name>
      <Grade>Grade1</Grade>
      <Number>13</Number>
    </ProductData>
    <ProductData>
      <ID>ID2</ID>
      <Name>Prod2</Name>
      <Grade>Grade2</Grade>
      <Number>12</Number>
    </ProductData>
  <ProductData>
      <ID>ID3</ID>
      <Name>Prod3</Name>
      <Grade>Grade3</Grade>
      <Number>10</Number>
    </ProductData>
  </Product>
  <Market>TestMarket</Market>
  <Quality>Tested</Quality>
  <Score>70</Score>
</Org>

要求是根据大于 10 的 <Number> 标记值将名为 <Status>Done</Status> 的节点添加到组 Product/ProductData。

如果 XML 中存在 ID3 且 <Number> 大于 10。<Status>Done</Status> 标记应仅添加到 ID3 中。

如果 ID3 无效(<Number>不大于 10)且 ID1 和 ID2 都存在于 XML 中且有效(<Number>大于 10),则在 ID2 中添加 <Status>Done</Status> 标记。

否则,如果 ID2 和 ID3 无效(<Number>大于 10)且 ID1 有效(<Number>大于 10),则将 <Status>Done</Status> 标记添加到 ID1。

ID1、ID2 和 ID3 的出现不是固定的。

下面是我的XSLT。在这里,我发现这很难实现第 2 点,即 ID1 和 ID2 都有效。我需要一个全局变量,如果一个验证匹配,请设置该变量的值。然后,我将使用 in 循环检查变量的值并跳过所有其他验证。我尝试了很多方法,但无法弄清楚这一点。我浏览了很多帖子,但没有提到在 for-each 中使用标志或在条件满足时打破循环。任何关于这方面的指导都将非常有帮助。

<xsl:template match="Org/Product">


  <xsl:for-each select="ProductData">
    <xsl:choose>
      <xsl:when test="ID ='ID1' and Number>10">
        <Status>Done</Status>
      </xsl:when>
      <xsl:when test="ID ='ID2' and Number>10">
        <Status>Done</Status>
      </xsl:when>
      <xsl:when test="ID ='ID3' and Number>10">
      <Status>Done</Status>
      </xsl:when>

    </xsl:choose>

  </xsl:for-each>

</xsl:template>

我正在寻找的输出如下

<Org>
  <Name>OrgName</Name>
  <Type>OrgType</Type>
  <Customer>OrgCust</Customer>
  <Product>
    <ProductData>
      <ID>ID1</ID>
      <Name>Prod1</Name>
      <Grade>Grade1</Grade>
      <Number>13</Number>
    </ProductData>
    <ProductData>
      <ID>ID2</ID>
      <Name>Prod2</Name>
      <Grade>Grade2</Grade>
      <Number>12</Number>
      <Status>Done</Status>
    </ProductData>
  <ProductData>
      <ID>ID3</ID>
      <Name>Prod3</Name>
      <Grade>Grade3</Grade>
      <Number>10</Number>
    </ProductData>
  </Product>
  <Market>TestMarket</Market>
  <Quality>Tested</Quality>
  <Score>70</Score>
</Org>

XSLT 的版本为 1.0。请帮忙。

xml xslt xml 解析 xslt-1.0

评论

0赞 michael.hor257k 6/8/2023
您显示的输出不符合您的要求:with has 大于 10。那么为什么将 the 添加到 with 中呢?ProductDataID3<Number>13</Number><Status>Done</Status>ProductDataID2
0赞 User_Earth_005 6/8/2023
不好意思。这是一个错别字。修复了它。如果 ID3 有效,则应仅在 ID3 中添加 Status 标记。
0赞 michael.hor257k 6/8/2023
不,您的输入与原来相同。
0赞 User_Earth_005 6/8/2023
我手动输入了它。不好意思。现已修复。请看。

答:

0赞 michael.hor257k 6/8/2023 #1

尝试类似的东西:

XSLT 1.0

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

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:variable name="id">
    <xsl:variable name="product" select="/Org/Product/ProductData" />
    <xsl:choose>
        <xsl:when test="$product[ID='ID3']/Number > 10">ID3</xsl:when>
        <xsl:when test="$product[ID='ID2']/Number > 10">ID2</xsl:when>
        <xsl:when test="$product[ID='ID1']/Number > 10">ID1</xsl:when>
    </xsl:choose>
</xsl:variable>

<xsl:template match="ProductData">
    <xsl:copy>
        <xsl:apply-templates/>
        <xsl:if test="ID = $id">
            <Status>Done</Status>
        </xsl:if>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

如果我们可以确定输入中列出的顺序(或者至少如果它们可以按所需的顺序按某些属性排序),我们可以更简单地定义变量 - 例如:ProductDataid

<xsl:variable name="id" select="/Org/Product/ProductData[Number > 10][last()]/ID" />

评论

0赞 User_Earth_005 6/8/2023
明白了。解决方案正在发挥作用。非常感谢。。。。我正在尝试使用 for-each,但看起来这是不可能的。模板匹配是正确的方法。再次感谢你。
0赞 michael.hor257k 6/8/2023
请记住,这不是一个“循环”。xsl:for-each
0赞 User_Earth_005 6/8/2023
理解。谢谢。