我有以下XML,它是一个12项管道分隔值。我只是为了解释而添加了空白节点中的空格,其他方面也是不存在的。
<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似乎很简单,可以解释)。
我不完全确定如何处理这个问题。
答案 0 :(得分: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() <= $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>
答案 1 :(得分: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>
答案 2 :(得分: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) > 1 or string-length($Two) >1 or string-length($Three) > 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>