如何使用XSLT1.0对纯文本输出进行右对齐?

如何使用XSLT1.0对纯文本输出进行右对齐?,xslt,Xslt,我正在处理一个如下所示的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">

我正在处理一个如下所示的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>
我还希望数值正确对齐。像这样:

Some Name              |   3
Another Name           |  10
A Third One            |  43
A Really Long Name     | 100
如何使用XSLT 1.0以这种方式对纯文本进行右对齐?

我在上找到了一些答案

描述的简单方法是执行以下操作:

<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>&#10;</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) &lt; $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) &lt; $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>

|



当然,您可以通过硬编码填充字符来稍微减小它们的足迹大小

以下是您的答案的更具可读性和效率的版本

<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>&#10;</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>&#10;</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>

|


另一个改进是动态计算最大字符串长度,而不必手动计算它。

<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>&#10;</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>&#10;</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>

|