如何使用XPath / Xsl将子元素与不同父元素下的同一子元素进行比较?

时间:2009-04-27 12:47:57

标签: xslt xpath

当SupplierId的值发生变化时,我需要使用xsl / xpath(版本1.0)来做一些特殊的事情(简化,比如插入一些虚拟文本)。我需要处理3种变化;

  1. 在第一个订单上执行某些操作 (SupplierId的第一次出现)
  2. 在OrderId O3(SupplierId从S1更改为S2)
  3. 时做什么
  4. 在最后一个订单(最后一次出现SupplierId)时执行某些操作
  5. <?xml version="1.0" encoding="utf-8"?>
    <Orders>
        <Order>
            <OrderId>O1</OrderId>
            <SupplierId>S1</SupplierId>
        </Order>
        <Order>
            <OrderId>O2</OrderId>
            <SupplierId>S1</SupplierId>
        </Order>
        <Order>
            <OrderId>O3</OrderId>
            <SupplierId>S2</SupplierId>
        </Order>
        <Order>
            <OrderId>O4</OrderId>
            <SupplierId>S2</SupplierId>
        </Order>
        <Order>
            <OrderId>O5</OrderId>
            <SupplierId>S2</SupplierId>
        </Order>
    </Orders>
    

    我尝试过使用previous-sibling,follow-sibling等,但还没有发现它。我很感激这个新手问题的任何帮助。

    沃利

3 个答案:

答案 0 :(得分:1)

这是一种自然而简单的解决方案

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

    <xsl:template match="Order[1]">
      First OrderId = <xsl:text/>
      <xsl:value-of select="OrderId"/>
    </xsl:template>

    <xsl:template match="Order[last()]">

      Last OrderId = <xsl:text/>
      <xsl:value-of select="OrderId"/>
    </xsl:template>

    <xsl:template match=
      "Order[not(position() = 1)]
         [not(SupplierId 
             = 
             preceding-sibling::Order[1]/SupplierId
              )
        ]">

      Changes in Order OrderId = <xsl:text/>
      <xsl:value-of select="OrderId"/>
         SupplierId = <xsl:text/>
         <xsl:value-of select="SupplierId"/>
      Previous Order OrderId = <xsl:text/>
      <xsl:value-of select=
        "preceding-sibling::Order[1]/OrderId"/>
                 SupplierId = <xsl:text/>
         <xsl:value-of select=
         "preceding-sibling::Order[1]/SupplierId"/>
    </xsl:template>

    <xsl:template match="text()"/>
</xsl:stylesheet>

在提供的XML文档上应用此转换时

<Orders>
    <Order>
        <OrderId>O1</OrderId>
        <SupplierId>S1</SupplierId>
    </Order>
    <Order>
        <OrderId>O2</OrderId>
        <SupplierId>S1</SupplierId>
    </Order>
    <Order>
        <OrderId>O3</OrderId>
        <SupplierId>S2</SupplierId>
    </Order>
    <Order>
        <OrderId>O4</OrderId>
        <SupplierId>S2</SupplierId>
    </Order>
    <Order>
        <OrderId>O5</OrderId>
        <SupplierId>S2</SupplierId>
    </Order>
</Orders>

产生了所需的结果

  First OrderId = O1

  Changes in Order OrderId = O3
     SupplierId = S2
  Previous Order OrderId = O2
             SupplierId = S1

  Last OrderId = O5

答案 1 :(得分:0)

假设根元素Orders,匹配每个条件的XPath表达式变为:

一个。 第一个订单(SupplierId首次出现)

XPath 1.0 - /Orders/Order[SupplierId][1]
XPath 2.0 - /Orders/Order[exists(SupplierId)][1]

在OrderId O3上(SupplierId从S1更改为S2)

/Orders/Order[OrderId = 'O3' and SupplierId = 'S2']

℃。 在最后一个订单(SupplierId的最后一次出现)

/Orders/Order[SupplierId][last()]

答案 2 :(得分:0)

您可以使用递归逐个降低订单列表,将前一个值与当前值进行比较(解决方案意味着文档顺序已经正确,因为它使用了以下兄弟轴):

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:template match="/Orders">
    <xsl:apply-templates select="Order[1]" mode="watch_SupplierId" />
  </xsl:template>

  <xsl:template match="Order" mode="watch_SupplierId">
    <xsl:param name="PrevValue" select="''" />

    <xsl:if test="string(SupplierId) != $PrevValue">
      <xsl:call-template name="DoSomething" />
    </xsl:if>

    <xsl:variable name="next" select="following-sibling::Order[1]" />
    <xsl:choose>
      <xsl:when test="$next">
        <xsl:apply-templates select="$next" mode="watch_SupplierId">
          <xsl:with-param name="PrevValue" select="string(SupplierId)" />
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="concat('last Order found: ', OrderId, '&#10;')" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="DoSomething">
    <xsl:value-of select="concat(
      '@SupplierId changed to &quot;' 
      , SupplierId/text() 
      , '&quot; in Order '
      , OrderId
      , '&#10;'
    )" />
  </xsl:template>

</xsl:stylesheet>

输出:

@SupplierId changed to "S1" in Order O1
@SupplierId changed to "S2" in Order O3
last Order found: O5