如何在XSLT中更新变量的值?

18

我在我的.xsl文件中声明了一个变量。现在我想用新值更新旧值。例如:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">

<xsl:output method="html" indent="yes"/>

  <xsl:template match="/">

    <Document>
      <xsl:variable name="topLevelHeadings" select = "//w:body/w:p[w:pPr[w:pStyle[@w:val='Heading1']]]"/>
      <xsl:variable name="beforeHeading" select="false()"/>


      <xsl:choose>

       <xsl:when test="$beforeHeading">
          <xsl:apply-templates select="//w:body/w:p">
            <xsl:with-param name="scope" select="count(//w:body/child::*)-1"/>
          </xsl:apply-templates>
       </xsl:when> 

        <xsl:when test="$topLevelHeadings">
          <xsl:variable name="beforeHeading" select="true()"/>
          <xsl:apply-templates select="$topLevelHeadings">
               <xsl:with-param name="scope" select="count(//w:body/child::*)-1"/>
          </xsl:apply-templates>
        </xsl:when>

        <xsl:otherwise>
          <xsl:apply-templates select="//w:body/w:p[w:r[w:t]]">
               <xsl:with-param name="scope" select="count(//w:body/child::*)-1"/>
          </xsl:apply-templates>
        </xsl:otherwise>
      </xsl:choose>
    </Document>
  </xsl:template>

  <xsl:template match="w:body/w:p">
    <xsl:param name = "scope"/>
    <xsl:variable name ="index" select="count(preceding-sibling::*)"/>
    <xsl:if test = "$index &lt;= $scope">
      <Paragraph>
        <xsl:attribute name="index">
          <xsl:value-of select="$index" />
        </xsl:attribute>
        <xsl:apply-templates select=".//w:r/w:t"/>
      </Paragraph>
    </xsl:if>
  </xsl:template>



    <xsl:template match="w:t">
        <xsl:value-of select="."/>
    </xsl:template>

   <xsl:template match="w:body/w:p">
    <xsl:param name = "scope"/>
    <xsl:variable name ="index" select="count(preceding-sibling::*)"/>
    <xsl:if test = "$index &lt;= $scope">
      <Paragraph>
        <xsl:attribute name="index">
          <xsl:value-of select="$index" />
        </xsl:attribute>
        <xsl:apply-templates select=".//w:r/w:t"/>
      </Paragraph>
    </xsl:if>
  </xsl:template>

    <xsl:template name="get-para-index">
        <xsl:param name="node"/>
        <xsl:value-of select="count($node/preceding-sibling::*)"/>
    </xsl:template>

    <xsl:template match="//w:body/w:p[w:pPr[w:pStyle]]">
    <xsl:param name = "scope"/>

        <xsl:variable name="currIndex" select="count(preceding-sibling::*)"/>            

        <xsl:if test="$currIndex &lt;= $scope"> 

            <!-- Get current heading value -->
            <xsl:variable name="currHeading" select="./w:pPr/w:pStyle/@w:val"/>

            <!-- Heading tag -->  
            <xsl:element name="{$currHeading}">

            <!-- Get heading text -->
            <Title>
              <xsl:attribute name ="index">
                <xsl:value-of select="$currIndex"/>
              </xsl:attribute>
             <xsl:apply-templates select=".//w:r/w:t"/> 
            </Title> 

            <!-- Get the scope of paragraphs inside this heading -->
            <xsl:variable name="nextHeading" select="following-sibling::w:p[w:pPr[w:pStyle[@w:val]]][1]"/>

            <xsl:variable name="paraScope">
                <xsl:choose>
                    <xsl:when test="$nextHeading">
                        <xsl:call-template name="get-para-index"> 
                            <xsl:with-param name="node" select="$nextHeading"/> 
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                         <xsl:value-of select="count(//w:body/child::*)"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>                       

            <!-- Handle paragraphs under this heading -->                    
            <xsl:apply-templates select="following-sibling::w:p[//w:r and not(w:pPr[w:pStyle])]">
                <xsl:with-param name="scope" select="$paraScope"/>
            </xsl:apply-templates>

            <!-- Get the first heading after current node at the same level -->
            <xsl:variable name="nextSibling" select="following-sibling::w:p[w:pPr[w:pStyle[@w:val=$currHeading]]][1]"/>

            <!-- Get its index -->
            <xsl:variable name="nextSiblingIndex">
                <xsl:choose>
                <xsl:when test="$nextSibling">                
                    <xsl:call-template name="get-para-index">
                        <xsl:with-param name="node" select="$nextSibling"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                <xsl:value-of select="$scope"/>
                </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>

            <!-- Set the scope of this node - this will be the smaller of nextSiblingIndex and current scope -->
            <xsl:variable name="currScope">
                <xsl:choose>
                    <xsl:when test="$nextSiblingIndex &lt; $scope">
                        <xsl:value-of select="$nextSiblingIndex"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$scope"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>

            <xsl:variable name="nextHead" select="concat('Heading', number(substring-after($currHeading, 'Heading'))+1)"/>            

            <!-- Get a list of child nodes (headings) for the current node -->
            <xsl:variable name="nextLevelHeadings" select="following-sibling::w:p[w:pPr[w:pStyle[@w:val=$nextHead]]]"/>            

            <!-- Apply recursively for next level headings within the scope -->
            <xsl:apply-templates select="$nextLevelHeadings">
                <xsl:with-param name="scope" select="$currScope"/> 
            </xsl:apply-templates>

            <!-- Close heading tag -->
            </xsl:element> 
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

你能否发布一个XML文件的示例,并可能描述一下你想要用它做什么? - Chris
@Chris:谢谢,我现在会更新它。 - Saravanan
2
这是一大堆代码。你能把它缩小成一个更简单的例子吗?这么庞大的规模可能会让一些本来可以回答的人望而却步。 - Gilles 'SO- stop being evil'
2个回答

18

如果你在transform过程中需要这样的行为,那么可能需要重新设计整个transform流程。此外,在没有展示输入文档和期望输出的情况下很难理解你想达成什么。

由于无法更新变量,你必须重新思考代码。最接近你要求的模式(我能够想象到的)是这样的:

    <xsl:template match="/">

        <xsl:variable name="topLevelHeadings" select="//w:body/w:p
                [w:pPr[w:pStyle[@w:val='Heading1']]]"/>

        <xsl:variable name="beforeHeading"> 
            <xsl:choose>
                <xsl:when test="$topLevelHeadings">
                    <xsl:value-of select="true()"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="false()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>

        <!-- your choose staff -->

        <!-- for instance --> 
        <xsl:if test="$beforeHeading='true'">
            <xsl:message>pass</xsl:message>
        </xsl:if>

    </xsl:template>

15

你不能这样做。XSLT是一种函数式编程语言,因此变量无法被修改。相反,使用递归来完成你想要的操作。


谢谢。我对XSLT很陌生。如何在这里使用递归来解决这个问题? - Saravanan
请描述您想要解决的问题:即从输入的XML文档转换为输出的XML文档。我们无法从错误的代码中逆向工程化您的需求。 - Michael Kay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接