我正在处理一个如下所示的XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="align-test.xsl"?>
<alignTest>
<item name="Some Name" number="3"></item>
<item name="Another Name" number="10"></item>
<item name="A Third One" number="43"></item>
<item name="A Really Long Name" number="100"></item>
</alignTest>
我的目标是输出一个纯文本文件,其中包含格式良好的表格。我已经想出如何使用这个样式表对齐和填充文本列和分隔符:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:for-each select="alignTest/item">
<!-- Scroll right. The next line keeps going, but might not look like it due to formatting -->
<xsl:value-of select="substring(concat(@name, ' '), 1, 22)"/>
<xsl:text> | </xsl:text>
<xsl:value-of select="@number"/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
哪个输出:
Some Name | 3
Another Name | 10
A Third One | 43
A Really Long Name | 100
我也希望数值正确对齐。像这样:
Some Name | 3
Another Name | 10
A Third One | 43
A Really Long Name | 100
如何使用XSLT 1.0以这种方式对纯文本进行右对齐?
答案 0 :(得分:4)
这是一个更易读,更有效的答案版本:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="item">
<xsl:call-template name="padRightSide">
<xsl:with-param name="stringToPad" select="@name"/>
<xsl:with-param name="totalLength" select="22"/>
</xsl:call-template>
<xsl:text>|</xsl:text>
<xsl:call-template name="padLeftSide">
<xsl:with-param name="stringToPad" select="@number"/>
<xsl:with-param name="totalLength" select="5"/>
</xsl:call-template>
<xsl:text> </xsl:text>
</xsl:template>
<!-- template to pad the left side of strings (and right justificy) -->
<xsl:template name="padLeftSide">
<xsl:param name="stringToPad"/>
<xsl:param name="totalLength"/>
<xsl:param name="padChar" select="' '"/>
<xsl:param name="padBuffer" select=
"concat($padChar,$padChar,$padChar,$padChar,$padChar,
$padChar,$padChar,$padChar,$padChar,$padChar
)"/>
<xsl:variable name="vNewString" select=
"concat($padBuffer, $stringToPad)"/>
<xsl:choose>
<xsl:when test="not(string-length($vNewString) >= $totalLength)">
<xsl:call-template name="padLeftSide">
<xsl:with-param name="stringToPad" select="$vNewString"/>
<xsl:with-param name="totalLength" select="$totalLength"/>
<xsl:with-param name="padChar" select="$padChar"/>
<xsl:with-param name="padBuffer" select="$padBuffer"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select=
"substring($vNewString,
string-length($vNewString) - $totalLength + 1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- template to pad the right side of strings -->
<xsl:template name="padRightSide">
<xsl:param name="totalLength"/>
<xsl:param name="padChar" select="' '"/>
<xsl:param name="stringToPad"/>
<xsl:param name="padBuffer" select=
"concat($padChar,$padChar,$padChar,$padChar,$padChar,
$padChar,$padChar,$padChar,$padChar,$padChar
)"/>
<xsl:variable name="vNewString" select=
"concat($stringToPad, $padBuffer)"/>
<xsl:choose>
<xsl:when test="not(string-length($vNewString) >= $totalLength)">
<xsl:call-template name="padRightSide">
<xsl:with-param name="stringToPad" select="$vNewString"/>
<xsl:with-param name="totalLength" select="$totalLength"/>
<xsl:with-param name="padChar" select="$padChar"/>
<xsl:with-param name="padBuffer" select="$padBuffer"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($vNewString,1,$totalLength)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
另一项改进是动态计算最大字符串长度而不必手动计算:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vNamesMaxLen">
<xsl:call-template name="maxLength">
<xsl:with-param name="pNodes"
select="/*/item/@name"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="vNumsMaxLen">
<xsl:call-template name="maxLength">
<xsl:with-param name="pNodes"
select="/*/item/@number"/>
</xsl:call-template>
</xsl:variable>
<xsl:template match="item">
<xsl:call-template name="padRightSide">
<xsl:with-param name="stringToPad"
select="@name"/>
<xsl:with-param name="totalLength"
select="$vNamesMaxLen+1"/>
</xsl:call-template>
<xsl:text>|</xsl:text>
<xsl:call-template name="padLeftSide">
<xsl:with-param name="stringToPad"
select="@number"/>
<xsl:with-param name="totalLength"
select="$vNumsMaxLen+1"/>
</xsl:call-template>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template name="maxLength">
<xsl:param name="pNodes" select="/.."/>
<xsl:for-each select="$pNodes">
<xsl:sort select="string-length()" data-type="number"
order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="string-length()"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<!-- template to pad the left side of strings (and right justificy) -->
<xsl:template name="padLeftSide">
<xsl:param name="stringToPad"/>
<xsl:param name="totalLength"/>
<xsl:param name="padChar" select="' '"/>
<xsl:param name="padBuffer" select=
"concat($padChar,$padChar,$padChar,$padChar,$padChar,
$padChar,$padChar,$padChar,$padChar,$padChar
)"/>
<xsl:variable name="vNewString" select=
"concat($padBuffer, $stringToPad)"/>
<xsl:choose>
<xsl:when test="not(string-length($vNewString) >= $totalLength)">
<xsl:call-template name="padLeftSide">
<xsl:with-param name="stringToPad" select="$vNewString"/>
<xsl:with-param name="totalLength" select="$totalLength"/>
<xsl:with-param name="padChar" select="$padChar"/>
<xsl:with-param name="padBuffer" select="$padBuffer"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select=
"substring($vNewString,
string-length($vNewString) - $totalLength + 1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- template to pad the right side of strings -->
<xsl:template name="padRightSide">
<xsl:param name="totalLength"/>
<xsl:param name="padChar" select="' '"/>
<xsl:param name="stringToPad"/>
<xsl:param name="padBuffer" select=
"concat($padChar,$padChar,$padChar,$padChar,$padChar,
$padChar,$padChar,$padChar,$padChar,$padChar
)"/>
<xsl:variable name="vNewString" select=
"concat($stringToPad, $padBuffer)"/>
<xsl:choose>
<xsl:when test="not(string-length($vNewString) >= $totalLength)">
<xsl:call-template name="padRightSide">
<xsl:with-param name="stringToPad" select="$vNewString"/>
<xsl:with-param name="totalLength" select="$totalLength"/>
<xsl:with-param name="padChar" select="$padChar"/>
<xsl:with-param name="padBuffer" select="$padBuffer"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($vNewString,1,$totalLength)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
我在this page找到了一些答案。
描述的简单方法是做类似的事情:
<xsl:value-of select="substring(concat(' ', @number), string-length(@number) + 1, 4)"/>
该页面还列出了几个用于填充左侧和右侧的模板。他们递归地称呼自己并填充适当的金额。 (请注意,如果请求的长度小于正在处理的字符串的长度,它们也将截断。)模板还取消了更改用于填充的字符的功能。
他们需要更多代码来实现,但可能更容易维护。这是使用两个模板更新的原始样式表的一个版本,以显示它们的用法:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:for-each select="alignTest/item">
<xsl:call-template name="padRightSide">
<xsl:with-param name="stringToPad" select="@name"></xsl:with-param>
<xsl:with-param name="totalLength" select="22"></xsl:with-param>
<xsl:with-param name="padCharacter" select="' '"></xsl:with-param>
</xsl:call-template>
<xsl:text>|</xsl:text>
<xsl:call-template name="padLeftSide">
<xsl:with-param name="stringToPad" select="@number"/>
<xsl:with-param name="totalLength" select="5"/>
<xsl:with-param name="padCharacteracter" select="' '"/>
</xsl:call-template>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
<!-- template to pad the left side of strings (and right justificy) -->
<xsl:template name="padLeftSide">
<xsl:param name="stringToPad"/>
<xsl:param name="totalLength"/>
<xsl:param name="padCharacteracter"/>
<xsl:choose>
<xsl:when test="string-length($stringToPad) < $totalLength">
<xsl:call-template name="padLeftSide">
<xsl:with-param name="stringToPad" select="concat($padCharacteracter,$stringToPad)"/>
<xsl:with-param name="totalLength" select="$totalLength"/>
<xsl:with-param name="padCharacteracter" select="$padCharacteracter"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($stringToPad,string-length($stringToPad) - $totalLength + 1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- template to pad the right side of strings -->
<xsl:template name="padRightSide">
<xsl:param name="padCharacter"/>
<xsl:param name="stringToPad"/>
<xsl:param name="totalLength"/>
<xsl:choose>
<xsl:when test="string-length($stringToPad) < $totalLength">
<xsl:call-template name="padRightSide">
<xsl:with-param name="padCharacter" select="$padCharacter"/>
<xsl:with-param name="stringToPad" select="concat($stringToPad,$padCharacter)"/>
<xsl:with-param name="totalLength" select="$totalLength"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($stringToPad,1,$totalLength)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
当然,您可以通过对填充字符进行硬编码来缩小其占用空间的大小。