XSLT 1.0:根据为前一个节点设置的值动态设置节点值

时间:2014-12-22 21:56:02

标签: xml xslt-1.0

我正在尝试根据可能为列表中的上一个节点设置或未设置的值为节点设置值。我需要使用XSLT 1.0,因为这是在IBM DataPower设备中完成的。除此之外还有更多内容,但我认为这会将其分解为最基本的内容。

我正在尝试识别没有前面数字范围且数字重叠的数字范围。一旦数字范围的IsUnique元素设置为true,其后面的所有其他重叠数字范围必须将其IsUnique元素设置为false。

如果我有一个如下所示的XML文档:

<Range>
    <Start>1</Start>
    <End>10</End>
    <IsUnique>true</IsUnique>
</Range>
<Range>
    <Start>11</Start>
    <End>20</End>
    <IsUnique>false</IsUnique>
</Range>
<Range>
    <Start>15</Start>
    <End>21</End>
    <IsUnique>false</IsUnique>
</Range>
<Range>
    <Start>25</Start>
    <End>30</End>
    <IsUnique>false</IsUnique>
</Range>

我希望它将第二个Range上的IsUnique值翻转为&#34; true&#34;因为它的范围与以前的任何范围都不重叠。我不希望它翻转第三个,因为它的范围与第二个重叠。我希望它将第四个翻转为真,因为它的范围不会与之前的任何范围重叠。我无法弄清楚如何&#34;看到&#34;在处理后续节点时,前一节点的IsUnique值已被翻转。这听起来很简单,我怀疑有一些我想念的简单解决方案,但我无法让它按预期工作。我假设我需要使用RTF和exsl:node-set(),但我没有找到合适的咒语来让它工作。谢谢!

1 个答案:

答案 0 :(得分:0)

这样怎么样?

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:template match="IsUnique">
    <xsl:copy>
        <xsl:value-of select="not(../../Range[generate-id()!=generate-id(current()/..) and Start &lt;= current()/../End and End >= current()/../Start])"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

应用于您的(更正的!)示例输入,结果为:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <Range>
      <Start>1</Start>
      <End>10</End>
      <IsUnique>true</IsUnique>
   </Range>
   <Range>
      <Start>11</Start>
      <End>20</End>
      <IsUnique>false</IsUnique>
   </Range>
   <Range>
      <Start>15</Start>
      <End>21</End>
      <IsUnique>false</IsUnique>
   </Range>
   <Range>
      <Start>25</Start>
      <End>30</End>
      <IsUnique>true</IsUnique>
   </Range>
</root>

加了:

上述内容将标记与任何其他范围重叠的任何范围,无论它们相对于彼此的位置如何。

要仅标记与之前范围重叠的范围(按文档顺序排列),请使用:

<xsl:template match="IsUnique">
    <xsl:copy>
        <xsl:value-of select="not(../preceding-sibling::Range[Start &lt;= current()/../End and End >= current()/../Start])"/>
    </xsl:copy>
</xsl:template>

修订:

重新定义任务后如下:

  1. 将每个范围标记为true或false(忽略现有标志);

  2. 如果(并且仅当)它与标记为true的先前范围重叠,则将范围标记为false;根据这个定义,第一个范围必须标记为真。

  3. XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common"
    extension-element-prefixes="exsl">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:template match="/root">
        <root>
            <xsl:call-template name="process-ranges">
                <xsl:with-param name="ranges" select="Range"/>
            </xsl:call-template>
        </root>
    </xsl:template>
    
    <xsl:template name="process-ranges">
        <xsl:param name="ranges"/>
        <xsl:param name="true-ranges" select="dummy-node"/>
        <xsl:param name="i" select="1"/>
        <xsl:param name="current-range" select="$ranges[$i]"/>
        <xsl:param name="unique" select="not(exsl:node-set($true-ranges)[Start &lt;= $current-range/End and End >= $current-range/Start])"/>
        <!-- output --> 
        <Range>
            <xsl:copy-of select="$current-range/Start | $current-range/End"/>
            <IsUnique>
                <xsl:value-of select="$unique"/>
            </IsUnique>
        </Range>
        <!-- recursive call -->
        <xsl:if test="$i &lt; count($ranges)">
            <xsl:call-template name="process-ranges">
                <xsl:with-param name="ranges" select="$ranges"/>
                <xsl:with-param name="true-ranges" select="$true-ranges | $current-range[$unique]"/>
                <xsl:with-param name="i" select="$i + 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    
    </xsl:stylesheet>
    

    <强>结果

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
       <Range>
          <Start>1</Start>
          <End>10</End>
          <IsUnique>true</IsUnique>
       </Range>
       <Range>
          <Start>11</Start>
          <End>20</End>
          <IsUnique>true</IsUnique>
       </Range>
       <Range>
          <Start>15</Start>
          <End>21</End>
          <IsUnique>false</IsUnique>
       </Range>
       <Range>
          <Start>25</Start>
          <End>30</End>
          <IsUnique>true</IsUnique>
       </Range>
    </root>
    

    进一步测试将是有序的。