2012-10-24 160 views
1

我有以下這是一個12入口管道分離值的XML。我只是爲了解釋而添加空白節點中的空格,並且其他方面不會存在。XSLT處理多個節點

<Base> 
    <Span>a|a| |a| |a| | |a| |a|a</Span> 
    <Span>b| | |b| | |b| | | | |b</Span> 
    <Span> | | | |c| | |c| | |c| </Span> 
</Base> 

我想從這個實現的輸出如下:

<Output> 
    <Period>a|b</Period> 
    <Period>a</Period> 
    <Period>a|b</Period> 
    <Period>c</Period> 
    <Period>a</Period> 
    <Period>b</Period> 
    <Period>c</Period> 
    <Period>a</Period> 
    <Period>a|c</Period> 
    <Period>a|b</Period> 
</Output> 

這是通過檢查,如果所有跨越的每一列都有一個值,如果有的話跨度在該列中的值實現一個條目被創建。因此,例如在跨越第一個欄包含a, b, -所以輸出變成<Period>a|b</Period>

我用XSLT 1.0工作,並在Span值可以是任何東西(A,B和C似乎簡單的解釋)。

我不完全確定如何解決這個問題。

回答

1

這XSLT 1.0樣式表...

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:exsl="http://exslt.org/common" 
    xmlns:so="http://stackoverflow.com/questions/13046157" 
    exclude-result-prefixes="xsl exsl so"> 
<xsl:output indent="yes" omit-xml-declaration="yes" /> 
<xsl:strip-space elements="*" /> 

<xsl:template match="/*"> 
    <Output> 
    <xsl:variable name="particles"> 
     <xsl:apply-templates select="Span" /> 
    </xsl:variable> 
    <xsl:variable name="col-count"> 
     <xsl:for-each select="exsl:node-set($particles)/so:particle"> 
     <xsl:sort select="@col" data-type="number" order="descending"/> 
     <xsl:if test="position()=1"> 
      <xsl:value-of select="@col"/> 
     </xsl:if> 
     </xsl:for-each> 
    </xsl:variable> 
    <xsl:for-each select="exsl:node-set($particles)/so:particle[position() &lt;= $col-count]"> 
     <xsl:variable name="col" select="position()" /> 
     <xsl:variable name="period"> 
     <xsl:for-each select="exsl:node-set($particles)/so:particle[@col=$col]"> 
      <xsl:sort select="@row" data-type="number" order="ascending"/> 
      <xsl:if test=". != ''"> 
      <xsl:value-of select="." /> 
      <xsl:if test="position() != last()"> 
       <xsl:value-of select="'|'" /> 
      </xsl:if> 
      </xsl:if> 
     </xsl:for-each> 
     </xsl:variable> 
     <xsl:if test="$period != ''"> 
     <Period><xsl:value-of select="$period" /></Period> 
     </xsl:if> 
    </xsl:for-each> 
    </Output> 
</xsl:template> 

<xsl:template match="Span" name="span"> 
    <xsl:param name="span-text" select="." /> 
    <xsl:param name="row" select="position()" /> 
    <xsl:param name="col" select="1" /> 
    <xsl:variable name="part" select=" 
    normalize-space(substring-before(concat($span-text, '|'), '|'))" /> 
    <xsl:if test="$part"> 
    <so:particle row="{$row}" col="{$col}"> 
     <xsl:value-of select="$part" /> 
    </so:particle> 
    </xsl:if> 
    <xsl:if test="contains($span-text,'|')"> 
    <xsl:call-template name="span"> 
     <xsl:with-param name="span-text" select="substring-after($span-text, '|')" /> 
     <xsl:with-param name="row" select="$row" /> 
     <xsl:with-param name="col" select="$col + 1" /> 
    </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 

......將改變這個...

<Base> 
    <Span>a|a| |a| |a| | |a| |a|a</Span> 
    <Span>b| | |b| | |b| | | | |b</Span> 
    <Span> | | | |c| | |c| | |c| </Span> 
</Base> 

...這個...

<Output> 
    <Period>a|b</Period> 
    <Period>a</Period> 
    <Period>a|b</Period> 
    <Period>c</Period> 
    <Period>a</Period> 
    <Period>b</Period> 
    <Period>c</Period> 
    <Period>a</Period> 
    <Period>a|c</Period> 
    <Period>a|b</Period> 
</Output> 
0

使用EXSLT以下應做到:不使用擴展

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:str="http://exslt.org/strings" 
    xmlns:exsl="http://exslt.org/common" 
    exclude-result-prefixes="str exsl" 
    version="1.0"> 

<xsl:output indent="yes"/> 

<xsl:variable name="table-rtf"> 
    <table> 
    <xsl:apply-templates select="Base/Span" mode="tokenize"/> 
    </table> 
</xsl:variable> 
<xsl:variable name="table" select="exsl:node-set($table-rtf)"/> 

<xsl:template match="Base"> 
    <Output> 
    <xsl:apply-templates select="$table/table/row[1]/cell" mode="col"/> 
    </Output> 
</xsl:template> 

<xsl:template match="row/cell" mode="col"> 
    <xsl:variable name="pos" select="position()"/> 
    <xsl:variable name="cols" select="$table/table/row/cell[$pos]"/> 
    <xsl:if test="$cols[normalize-space()]"> 
    <Period> 
     <xsl:for-each select="$cols[normalize-space()]"> 
     <xsl:if test="position() > 1">|</xsl:if> 
     <xsl:value-of select="."/> 
     </xsl:for-each> 
    </Period> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="Span" mode="tokenize"> 
    <row> 
    <xsl:for-each select="str:tokenize(., '|')"> 
     <cell> 
     <xsl:value-of select="normalize-space()"/> 
     </cell> 
    </xsl:for-each> 
    </row> 
</xsl:template> 

</xsl:stylesheet> 

例如與xsltproc的,你可以將輸入

<Base> 
    <Span>a|a| |a| |a| | |a| |a|a</Span> 
    <Span>b| | |b| | |b| | | | |b</Span> 
    <Span> | | | |c| | |c| | |c| </Span> 
</Base> 

到結果

<Output> 
    <Period>a|b</Period> 
    <Period>a</Period> 
    <Period>a|b</Period> 
    <Period>c</Period> 
    <Period>a</Period> 
    <Period>b</Period> 
    <Period>c</Period> 
    <Period>a</Period> 
    <Period>a|c</Period> 
    <Period>a|b</Period> 
</Output> 
0

此模板(XSLT 1.0)

<?xml version="1.0" encoding="utf-8"?> 
<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:output method="xml" indent="yes"/> 

    <xsl:template match="Base"> 
     <Output> 
      <xsl:call-template name="Format"> 
      <xsl:with-param name="One" select="Span[1]" /> 
      <xsl:with-param name="Two" select="Span[2]" /> 
      <xsl:with-param name="Three" select="Span[3]" /> 
      </xsl:call-template> 
     </Output> 
    </xsl:template> 
    <xsl:template name="Format"> 
    <xsl:param name="One" /> 
    <xsl:param name="Two" /> 
    <xsl:param name="Three" /> 
    <xsl:param name="SOne" select="substring-before($One,'|')"/> 
    <xsl:param name="STwo" select="substring-before($Two,'|')"/> 
    <xsl:param name="SThree" select="substring-before($Three,'|')"/> 
    <xsl:choose> 
     <xsl:when test="string-length($One) &gt; 1 or string-length($Two) &gt;1 or string-length($Three) &gt; 1"> 
     <xsl:if test="not($SOne='' and $STwo ='' and $SThree='')"> 
      <Period> 
      <xsl:call-template name="FormatPipes"> 
       <xsl:with-param name="One" select="$SOne" /> 
       <xsl:with-param name="Two" select="$STwo" /> 
       <xsl:with-param name="Three" select="$SThree" /> 
      </xsl:call-template> 
      </Period> 
     </xsl:if> 
     <xsl:call-template name="Format"> 
      <xsl:with-param name="One" select="substring-after($One,'|')" /> 
      <xsl:with-param name="Two" select="substring-after($Two,'|')" /> 
      <xsl:with-param name="Three" select="substring-after($Three,'|')" /> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:if test="not($One='' and $Two ='' and $Three='')"> 
      <Period> 
      <xsl:call-template name="FormatPipes"> 
       <xsl:with-param name="One" select="$One" /> 
       <xsl:with-param name="Two" select="$Two" /> 
       <xsl:with-param name="Three" select="$Three" /> 
      </xsl:call-template> 
      </Period> 
     </xsl:if> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template name="FormatPipes"> 
    <xsl:param name="One" /> 
    <xsl:param name="Two" /> 
    <xsl:param name="Three" /> 
    <xsl:variable name="node"> 
     <root> 
     <xsl:if test="not($One='')"> 
      <a><xsl:value-of select="$One"/></a> 
     </xsl:if> 
     <xsl:if test="not($Two='')"> 
      <a><xsl:value-of select="$Two"/></a> 
     </xsl:if> 
     <xsl:if test="not($Three='')"> 
      <a><xsl:value-of select="$Three"/></a> 
     </xsl:if> 
     </root> 
    </xsl:variable> 
    <xsl:apply-templates select="msxsl:node-set($node)"/> 
    </xsl:template> 

    <xsl:template match="root"> 
    <xsl:for-each select="a"> 
    </xsl:for-each> 
    <xsl:apply-templates select="a"/> 
    </xsl:template> 

    <xsl:template match="a"> 
    <xsl:value-of select="."/> 
    <xsl:if test="position() != last()">|</xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

會產生這種正確的輸出

<?xml version="1.0" encoding="utf-8"?> 
<Output> 
    <Period>a|b</Period> 
    <Period>a</Period> 
    <Period>a|b</Period> 
    <Period>c</Period> 
    <Period>a</Period> 
    <Period>b</Period> 
    <Period>c</Period> 
    <Period>a</Period> 
    <Period>a|c</Period> 
    <Period>a|b</Period> 
</Output> 
+0

1.相反,你的說法,你**使用延長**(msxsl:節點集); 2.這隻適用於Microsoft XSLT處理器; 3.實際輸出不像您列出的那樣。當額外的空白空間進入時,您的解決方案不起作用。 –

+0

另一個問題是,您的解決方案是針對3個輸入的跨度行進行硬編碼的。雖然不明確,但我認爲這是不可能的。 –

+0

在解釋中值得注意的是肖恩我聲明瞭爲簡化解釋而添加了空白,並且在實際實現中並不存在。 – Mike