更新xslt中的变量

更新xslt中的变量,xslt,Xslt,XML: 约翰 A. xy 约翰 B 10 约翰,杰德 A、 Y 1. 约翰,杰德 A C,X 约翰,杰德 C D,Y 约翰 A B xy XSLT: 我将包含单个值的cell2存储在atomictest变量中 检查Cell2是否包含逗号。如果为true,则基于逗号标记Cell2,并检查原子测试->中是否存在标记Cell2值,如果否,则将Cell2和Cell1值添加到输出中 我想将输出中新添加的Cell1和Cell2值更新到atomictest变量,这样,如果下次遇到相同的Cell2值,

XML:


约翰
A.
xy
约翰
B
10
约翰,杰德
A、 Y
1.
约翰,杰德
A C,X
约翰,杰德
C D,Y
约翰
A B
xy
XSLT:


  • 我将包含单个值的cell2存储在atomictest变量中
  • 检查Cell2是否包含逗号。如果为true,则基于逗号标记Cell2,并检查原子测试->中是否存在标记Cell2值,如果否,则将Cell2和Cell1值添加到输出中
  • 我想将输出中新添加的Cell1和Cell2值更新到atomictest变量,这样,如果下次遇到相同的Cell2值,我就需要跳过它。怎么做
  • 我得到的输出:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
        <xsl:output method="xml" encoding="UTF-8" indent="no"/>
        <xsl:template match="/">
            <xsl:apply-templates select="sample"/>
        </xsl:template>
        <xsl:template match="sample">
            <xsl:variable name="atomictest">
                <!--Store the test containing only one value in cell2-->
                <xsl:copy-of select="test[not(contains(Cell2,',')) or not(contains(Cell2,' '))]"/>
            </xsl:variable>
            <xsl:variable name="copy">
                <xsl:apply-templates select="test">
                    <xsl:with-param name="atomictest" select="$atomictest"/>
                </xsl:apply-templates>
            </xsl:variable>
        </xsl:template>
        <xsl:template match="test">
            <xsl:param name="atomictest"/>
            <xsl:choose>
                <xsl:when test="contains(Cell2,',')">
                    <xsl:variable name="Cell1">
                        <xsl:copy-of select="Cell1"/>
                    </xsl:variable>
                    <!-- tokenize cell2 based on comma -->
                    <xsl:for-each select="tokenize(Cell2,',')">
                        <xsl:variable name="str">
                            <xsl:value-of select="."/>
                        </xsl:variable>
                        <xsl:variable name="pos">
                            <xsl:value-of select="position()"/>
                        </xsl:variable>
                        <xsl:choose>
                            <!-- If cell2 contains space -->
                            <xsl:when test="contains(.,' ')">
                                <!-- tokenize cell2 based on comma -->
                                <xsl:for-each select="tokenize(.,' ')">
                                    <xsl:variable name="str">
                                        <xsl:value-of select="."/>
                                    </xsl:variable>
                                    <!-- if cell2 value not contained in the atomic collected -->
                                    <xsl:if test="not($atomictest/test[normalize-space(Cell2/text())=normalize-space($str)])">
                                        <!--Store Cell2 value -->
                                        <xsl:variable name="Cell2">
                                            <xsl:value-of select="."/>
                                        </xsl:variable>
                                        <!-- tokenize cell1-->
                                        <xsl:for-each select="tokenize($Cell1/Cell1,',')">
                                            <xsl:if test="position()=$pos">
                                                <test>
                                                    <Cell1>
                                                        <xsl:value-of select="."/>
                                                    </Cell1>
                                                    <Cell2>
                                                        <xsl:value-of select="$Cell2"/>
                                                    </Cell2>
                                                </test>
                                            </xsl:if>
                                        </xsl:for-each>
                                    </xsl:if>
                                </xsl:for-each>
                            </xsl:when>
                            <xsl:otherwise>
                                <!-- if cell2 doesnot contains space -->
                                <xsl:if test="not($atomictest/test[normalize-space(Cell2/text())=normalize-space($str)])">
                                    <xsl:variable name="Cell2">
                                        <xsl:value-of select="."/>
                                    </xsl:variable>
                                    <xsl:for-each select="tokenize($Cell1/Cell1,',')">
                                        <xsl:if test="position()=$pos">
                                            <test>
                                                <Cell1>
                                                    <xsl:value-of select="."/>
                                                </Cell1>
                                                <Cell2>
                                                    <xsl:value-of select="$Cell2"/>
                                                </Cell2>
                                            </test>
                                        </xsl:if>
                                    </xsl:for-each>
                                </xsl:if>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </xsl:when>
                <xsl:when test="contains(Cell2,' ')">
                    <xsl:variable name="Cell1">
                        <xsl:copy-of select="Cell1"/>
                    </xsl:variable>
                    <!-- tokenize cell2 based on space or comma -->
                    <xsl:for-each select="tokenize(Cell2,' ')">
                        <xsl:variable name="str">
                            <xsl:value-of select="."/>
                        </xsl:variable>
                        <xsl:variable name="pos">
                            <xsl:value-of select="position()"/>
                        </xsl:variable>
                        <!-- if cell2 value not contained in the atomic rows collected -->
                        <xsl:if test="not($atomictest/test[normalize-space(Cell2/text())=normalize-space($str)])">
                            <xsl:if test="position()=$pos">
                                <test>
                                    <Cell1>
                                        <xsl:value-of select="$Cell1"/>
                                    </Cell1>
                                    <Cell2>
                                        <xsl:value-of select="$str"/>
                                    </Cell2>
                                </test>
                            </xsl:if>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:when>
                <xsl:otherwise>
                    <test>
                        <Cell1>
                            <xsl:value-of select="Cell1"/>
                        </Cell1>
                        <Cell2>
                            <xsl:value-of select="Cell2"/>
                        </Cell2>
                    </test>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    </xsl:stylesheet>
    
    
    约翰
    A.
    约翰
    B
    玉
    Y
    约翰
    C
    玉
    X
    约翰
    C
    约翰
    D
    玉
    Y
    
    结果输出应如下所示:

    <test>
        <Cell1>John</Cell1>
        <Cell2>A</Cell2>
    </test>
    <test>
        <Cell1>John</Cell1>
        <Cell2>B</Cell2>
    </test>
    <test>
        <Cell1>Jade</Cell1>
        <Cell2>Y</Cell2>
    </test>
    <test>
        <Cell1>John</Cell1>
        <Cell2>C</Cell2>
    </test>
    <test>
        <Cell1>Jade</Cell1>
        <Cell2>X</Cell2>
    </test>
    <test>
        <Cell1>John</Cell1>
        <Cell2>C</Cell2>
    </test>
    <test>
        <Cell1>John</Cell1>
        <Cell2>D</Cell2>
    </test>
    <test>
        <Cell1>Jade</Cell1>
        <Cell2>Y</Cell2>
    </test>
    
    
    约翰
    A.
    约翰
    B
    玉
    Y
    约翰
    C
    玉
    X
    约翰
    D
    
    变量在XSLT中是只读的。也就是说,您只能对其进行一次签名。之后,它们是只读的。

    此XSLT 2.0样式表

    <test>
            <Cell1>John</Cell1>
            <Cell2>A</Cell2>
        </test>
        <test>
            <Cell1>John</Cell1>
            <Cell2>B</Cell2>
        </test>
        <test>
            <Cell1>Jade</Cell1>
            <Cell2>Y</Cell2>
        </test>
        <test>
            <Cell1>John</Cell1>
            <Cell2>C</Cell2>
        </test>
        <test>
            <Cell1>Jade</Cell1>
            <Cell2>X</Cell2>
        </test>
        <test>
            <Cell1>John</Cell1>
            <Cell2>D</Cell2>
        </test>
    
    
    
    …将转换此输入

    <xsl:stylesheet version="2.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:temp="http://stackoverflow.com/questions/12673307"
      exclude-result-prefixes="xsl temp">
    <xsl:output omit-xml-declaration="yes" indent="yes" />
    <xsl:strip-space elements="*" />  
    
    <xsl:variable name="phase-1-output">
      <temp:tests>
        <xsl:apply-templates select="/*/test" mode="phase-1" />
      </temp:tests>
    </xsl:variable>
    
    <xsl:variable name="phase-2-output">
      <xsl:apply-templates select="$phase-1-output" mode="phase-2" />
    </xsl:variable>
    
    <xsl:template match="/">
     <xsl:copy-of select="$phase-2-output"/>
    </xsl:template>
    
    <xsl:template match="*" mode="phase-1" />
    
    <xsl:template match="test[Cell1!=''][Cell2!='']" mode="phase-1">
      <xsl:variable name="cell2" select="tokenize(Cell2,',')" />
      <xsl:for-each select="tokenize(Cell1,',')" >
        <xsl:variable name="cell1-pos" select="position()" />
        <xsl:variable name="cell1" select="." />
        <xsl:for-each select="tokenize($cell2[$cell1-pos],' ')">
          <temp:test>
            <temp:Cell1><xsl:value-of select="$cell1" /></temp:Cell1>
            <temp:Cell2><xsl:value-of select="." /></temp:Cell2>
          </temp:test>
        </xsl:for-each>
      </xsl:for-each>
    </xsl:template>
    
    <xsl:template match="temp:tests" mode="phase-2">
      <xsl:for-each-group select="temp:test" group-by="concat(temp:Cell1,'|',temp:Cell2)">
        <test>
          <Cell1><xsl:value-of select="substring-before(current-grouping-key(),'|')" /></Cell1>
          <Cell2><xsl:value-of select="substring-after(current-grouping-key(),'|')" /></Cell2>
        </test>
      </xsl:for-each-group>
    </xsl:template>
    
    </xsl:stylesheet>
    
    
    约翰
    A.
    xy
    约翰
    B
    10
    约翰,杰德
    A、 Y
    1.
    约翰,杰德
    A C,X
    约翰,杰德
    C D,Y
    约翰
    A B
    xy
    
    …变成

    <sample>
        <test>
            <Cell1>John</Cell1>
            <Cell2>A</Cell2>
            <Cell4>xy</Cell4>
        </test>
        <test>
            <Cell1>John</Cell1>
            <Cell2>B</Cell2>
            <Cell6>10</Cell6>
        </test>
        <test>
            <Cell1>John,Jade</Cell1>
            <Cell2>A,Y</Cell2>
            <Cell4>1</Cell4>
        </test>
        <test>
            <Cell1>John,Jade</Cell1>
            <Cell2>A C,X</Cell2>
        </test>
        <test>
            <Cell1>John,Jade</Cell1>
            <Cell2>C D,Y</Cell2>
        </test>
        <test>
            <Cell1>John</Cell1>
            <Cell2>A B</Cell2>
            <Cell4>xy</Cell4>
        </test>
    </sample>
    
    
    约翰
    A.
    约翰
    B
    玉
    Y
    约翰
    C
    玉
    X
    约翰
    D
    

    替代解决方案 这里有一个替代的单相解决方案。它更简单,但适应性较差

    <test>
       <Cell1>John</Cell1>
       <Cell2>A</Cell2>
    </test>
    <test>
       <Cell1>John</Cell1>
       <Cell2>B</Cell2>
    </test>
    <test>
       <Cell1>Jade</Cell1>
       <Cell2>Y</Cell2>
    </test>
    <test>
       <Cell1>John</Cell1>
       <Cell2>C</Cell2>
    </test>
    <test>
       <Cell1>Jade</Cell1>
       <Cell2>X</Cell2>
    </test>
    <test>
       <Cell1>John</Cell1>
       <Cell2>D</Cell2>
    </test>
    
    
    
    注 两种解决方案均基于以下假设:

  • Cell1和Cell2具有相同的逗号计数
  • Cell1将永远不包含管道(“|”)字符

  • XSLT是一种函数式语言。除此之外,这意味着变量无法更新。XSLT模板/函数库以惊人的简单性解决了非常具有挑战性的任务,这些任务可能比相应的命令式语言解决方案更简单、更易于理解和维护,并且效率不低于相应的命令式语言解决方案。您想要生成的结果可以使用功能齐全的代码生成,而不是更新变量。但请提供一个简短的例子,以便人们有时间阅读和阅读
    <test>
       <Cell1>John</Cell1>
       <Cell2>A</Cell2>
    </test>
    <test>
       <Cell1>John</Cell1>
       <Cell2>B</Cell2>
    </test>
    <test>
       <Cell1>Jade</Cell1>
       <Cell2>Y</Cell2>
    </test>
    <test>
       <Cell1>John</Cell1>
       <Cell2>C</Cell2>
    </test>
    <test>
       <Cell1>Jade</Cell1>
       <Cell2>X</Cell2>
    </test>
    <test>
       <Cell1>John</Cell1>
       <Cell2>D</Cell2>
    </test>
    
    <xsl:stylesheet version="2.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes" />
    <xsl:strip-space elements="*" />  
    
    <xsl:template match="/">
      <xsl:for-each select="
         distinct-values(
           for $t in /*/test,
               $p1 in 1 to  count( tokenize($t/Cell1,',')),
               $cell1 in           tokenize($t/Cell1,',')[$p1],
               $cell2 in tokenize( tokenize($t/Cell2,',')[$p1], ' ') return
                   concat($cell1,'|',$cell2))">
        <test>
          <Cell1><xsl:value-of select="substring-before(.,'|')" /></Cell1>
          <Cell2><xsl:value-of select="substring-after( .,'|')" /></Cell2>
        </test>
      </xsl:for-each>  
    </xsl:template>
    
    </xsl:stylesheet>