让我的外环意识到内环的存在

时间:2011-02-25 16:56:23

标签: xml xslt loops

我认为我的标题基本上描述了我现在在XSLT中所坚持的内容。但更确切地说,我的意思是“如何使外部循环知道内部DOES在XSLT中执行与否”。请原谅我,因为我是这个领域的初学者。

首先,我的初始xml是一个空白的,我的XSLT基本上将从大量的xml数据文件中获取数据,并使用我想要的标记创建一个生成的xml文件。具体来说,我遇到的问题发生在两个模板“Outer”和“Inner”中,这两个模板本身就是循环结构,它们试图遍历某些xml文件的每一行。流的控制是直截了当的:我在主XSLT中调用Outer,然后我们进入Outer的“for-each”循环,在这个Outer的每次运行中,我将调用“Inner”,所以它是一个循环-within-Loop Structure。

现在,我们可以忽略所有其他的东西,但只知道一旦我进入外循环,我将创建一个“HL”段,然后内部被调用并进入内循环,并且对于每次内部运行,我也将创建一个“HL”段。有一点需要注意的是,除非满足某些条件,否则不能输入Inner,因此可能存在根本没有输入Inner的情况,并且所有HL段都是在Outer中单独创建的。

我想要计算这个HL片段,我将分享一小段代码让你有个主意。

外圈:

<xsl:template name="Outer">
  <xsl:for-each select="$rechca//d_claim_rechca_export_xml_row">
    <xsl:variable name="rechca_claim_no" select=claim_number/>
       <HL01>
         <xsl:if test="$indicator=0">                                    

              <xsl:value-of select="position()+1>
          </xsl:if>
       </HL01>
    ....

  <xsl:for-each select="$rechcf//d_claim_rechcf_export_xml_row">
   <xsl:if test="claim_number=$rechca_claim_number">
     <xsl:call-template name="Inner">
      <xsl:with-param name="HLcounter" select="position()+1"/>
      </xsl:call-template>
   </xsl:if> 
  </xsl:for-each>

 </xsl:for-each> 
</xsl:template>

内环:                        

  <xsl:for-each select="$rechcf//d_claim_rechcf_export_xml_row[claim_number =$claimno and sequence_number = 1]">
 <Inner>
 <HL>
   <HL01>  
      <xsl:number value ="position()+$Hcount"/>
    </HL01>
    ....

目前,$ rechca中有两行,$ rechcf中只有一行满足两个循环,因此外循环重复两次而Inner只执行一次。因此,所需的输出应为

<Outer>  
  <HL>
    <HL01>2</HL01>
  </HL>
     <Inner>
         <HL01>3</HL01>     
     </Inner>
  <HL>
    <HL01>4</HL01>
  </HL>
 </Outer>

但是好的输出是:

 <Outer>  
  <HL>
    <HL01>2</HL01>
  </HL>
     <Inner>
         <HL01>3</HL01>     
     </Inner>
  <HL>
    <HL01>3</HL01>
  </HL>
 </Outer>

如果没有这个内循环,事情就会完美无缺。但是目前外循环并不知道内循环的存在:一旦内部被调用,那么当它将控制返回到外循环时,顶部不应该包含“position()+ 1”而是“position”( )+2“而不是(因为Inner在进入这个新外部之前被调用了一次,因此在那里创建了一个新的HL段)。如您所见,我创建了一个名为“指标”的变量。在Java / C ++中,我只是将此指标更新为0以外的其他值,每次输入inner时,将其设置为1。然后在Outer的HL01进行测试,以确定要添加到position()的正确值。

真的卡在这里,请帮忙!感谢。

1 个答案:

答案 0 :(得分:1)

最简单的解决方案,无需解释命令式和声明性范式之间的差异,是一个两阶段的转换。这个样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="msxsl">
    <xsl:template match="/">
        <xsl:variable name="vRTF-FirstPass">
            <Outer>
                <HL>
                    <HL01/>
                </HL>
                <Inner>
                    <HL01/>
                </Inner>
                <HL>
                    <HL01/>
                </HL>
            </Outer>
        </xsl:variable>
        <xsl:apply-templates
             select="msxsl:node-set($vRTF-FirstPass)/node()"
             mode="second-pass"/>
    </xsl:template>
    <xsl:template match="node()|@*" mode="second-pass">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" mode="second-pass"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="HL01" mode="second-pass">
        <xsl:copy>
            <xsl:variable name="vPosition">
                <xsl:number level="any"/>
            </xsl:variable>
            <xsl:value-of select="$vPosition + 1"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

使用任何输入(未使用),输出:

<Outer>
    <HL>
        <HL01>1</HL01>
    </HL>
    <Inner>
        <HL01>2</HL01>
    </Inner>
    <HL>
        <HL01>3</HL01>
    </HL>
</Outer>

注意:使用node-set()扩展功能(为您的XSLT处理器实现寻找正确的命名空间URI,或者只是将您的环境升级到XSLT 2.0并忘记node-set() )。模式以防万一。当然,您应该在$vRTF-FirstPass变量中输出所有您想要的输出,无论是apply-templatescall-template还是......等等。

编辑:您可以将“HL01”规则替换为其他类似但更短的内容模板:

<xsl:copy>
    <xsl:value-of select="count(preceding::HL01) + 2"/>
</xsl:copy>