如何计算 node-set 的最大值 string-length?
How to calculate max string-length of a node-set?
我正在尝试使用 XSLT 将 XML 文档转换为供人们使用的纯文本表格。我正在使用 xsltproc
,它仅实现 XSLT 1.0(因此 max
实际上来自 EXSLT)。
我尝试了下面的方法,但是 commented-out 定义失败了,因为 string-length
returns 只有一个值(first 的长度节点的字符串值),而不是 max
想要的 node-set。
转型:
<?xml version="1.0" encoding="utf-8"?>
<!-- vim: set sts=2 sw=2: -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:math="http://exslt.org/math" xmlns:str="http://exslt.org/strings">
<xsl:output method="text"/>
<xsl:template match="/root">
<!-- <xsl:variable name="max_a_width" select="math:max(string-length(data/@a))"/> -->
<xsl:variable name="max_a_width" select="string-length(data/@a)"/>
<xsl:text>+-</xsl:text><xsl:value-of select="str:padding($max_a_width, '-')"/><xsl:text>-+ </xsl:text>
<xsl:for-each select="data">
<xsl:text>| </xsl:text><xsl:value-of select="@a"/><xsl:value-of select="str:padding($max_a_width - string-length(@a), ' ')"/><xsl:text> | </xsl:text>
</xsl:for-each>
<xsl:text>+-</xsl:text><xsl:value-of select="str:padding($max_a_width, '-')"/><xsl:text>-+ </xsl:text>
</xsl:template>
</xsl:stylesheet>
输入:
<?xml version="1.0" encoding="utf-8"?>
<!-- vim: set sts=2 sw=2: -->
<root>
<data a="aa"/>
<data a="aaa"/>
<data a="a"/>
</root>
输出:
+----+
| aa |
| aaa |
| a |
+----+
为了让右边框对齐,我需要在变量中有实际的最大值。 (在我的真实示例中,我将有列 headers 和多个列,但它们不是重现问题所必需的)。
如果更容易找到解决方案,我可以保证数据值永远不会包含空格。
<xsl:variable name="max_a_width">
<xsl:for-each select="data">
<xsl:sort select="string-length(@a)" data-type="number" />
<xsl:if test="position() = last()">
<xsl:value-of select="string-length(@a)" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
这是在 XSLT 1.0 中从派生值的有序列表中选取的一般方法。
如果您想从实际(本机可排序的)值中选择 minimum/maximum,您可以走捷径:
<xsl:variable name="max_a" select="//a[not(. < //a)][1]" />
这是一个简单的递归模板。 运行 使用相同的 XSLT 文件作为输入来测试它。使用 XSLT 2 或 XQuery 这当然更容易...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template name="maxlen">
<xsl:param name="input" />
<xsl:param name="max-so-far" select="0" />
<xsl:choose>
<xsl:when test="not($input)">
<xsl:value-of select="$max-so-far" />
</xsl:when>
<xsl:when test="string-length($input[1]) > $max-so-far">
<xsl:call-template name="maxlen">
<xsl:with-param name="input" select="$input[position() > 1]" />
<xsl:with-param name="max-so-far"
select="string-length($input[1])" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="maxlen">
<xsl:with-param name="input" select="$input[position() > 1]" />
<xsl:with-param name="max-so-far" select="$max-so-far" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:variable name="input">
<test>
<string>123456789012345678901234</string>
<string>12345678901234</string>
<string>1234567890</string>
<string>12345678901234567890123456</string>
</test>
</xsl:variable>
<xsl:template match="/">
<output>
<xsl:call-template name="maxlen">
<xsl:with-param name="input" select="//test/string" />
</xsl:call-template>
</output>
</xsl:template>
</xsl:stylesheet>
这是如何使用 EXSLT math:max()
:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:math="http://exslt.org/math"
xmlns:str="http://exslt.org/strings">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/root">
<xsl:variable name="lengths">
<xsl:for-each select="data">
<length><xsl:value-of select="string-length(@a)"/></length>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="max_a_width" select="math:max(exsl:node-set($lengths)/length)"/>
<!-- the rest -->
</xsl:template>
</xsl:stylesheet>
我正在尝试使用 XSLT 将 XML 文档转换为供人们使用的纯文本表格。我正在使用 xsltproc
,它仅实现 XSLT 1.0(因此 max
实际上来自 EXSLT)。
我尝试了下面的方法,但是 commented-out 定义失败了,因为 string-length
returns 只有一个值(first 的长度节点的字符串值),而不是 max
想要的 node-set。
转型:
<?xml version="1.0" encoding="utf-8"?>
<!-- vim: set sts=2 sw=2: -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:math="http://exslt.org/math" xmlns:str="http://exslt.org/strings">
<xsl:output method="text"/>
<xsl:template match="/root">
<!-- <xsl:variable name="max_a_width" select="math:max(string-length(data/@a))"/> -->
<xsl:variable name="max_a_width" select="string-length(data/@a)"/>
<xsl:text>+-</xsl:text><xsl:value-of select="str:padding($max_a_width, '-')"/><xsl:text>-+ </xsl:text>
<xsl:for-each select="data">
<xsl:text>| </xsl:text><xsl:value-of select="@a"/><xsl:value-of select="str:padding($max_a_width - string-length(@a), ' ')"/><xsl:text> | </xsl:text>
</xsl:for-each>
<xsl:text>+-</xsl:text><xsl:value-of select="str:padding($max_a_width, '-')"/><xsl:text>-+ </xsl:text>
</xsl:template>
</xsl:stylesheet>
输入:
<?xml version="1.0" encoding="utf-8"?>
<!-- vim: set sts=2 sw=2: -->
<root>
<data a="aa"/>
<data a="aaa"/>
<data a="a"/>
</root>
输出:
+----+
| aa |
| aaa |
| a |
+----+
为了让右边框对齐,我需要在变量中有实际的最大值。 (在我的真实示例中,我将有列 headers 和多个列,但它们不是重现问题所必需的)。
如果更容易找到解决方案,我可以保证数据值永远不会包含空格。
<xsl:variable name="max_a_width">
<xsl:for-each select="data">
<xsl:sort select="string-length(@a)" data-type="number" />
<xsl:if test="position() = last()">
<xsl:value-of select="string-length(@a)" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
这是在 XSLT 1.0 中从派生值的有序列表中选取的一般方法。
如果您想从实际(本机可排序的)值中选择 minimum/maximum,您可以走捷径:
<xsl:variable name="max_a" select="//a[not(. < //a)][1]" />
这是一个简单的递归模板。 运行 使用相同的 XSLT 文件作为输入来测试它。使用 XSLT 2 或 XQuery 这当然更容易...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template name="maxlen">
<xsl:param name="input" />
<xsl:param name="max-so-far" select="0" />
<xsl:choose>
<xsl:when test="not($input)">
<xsl:value-of select="$max-so-far" />
</xsl:when>
<xsl:when test="string-length($input[1]) > $max-so-far">
<xsl:call-template name="maxlen">
<xsl:with-param name="input" select="$input[position() > 1]" />
<xsl:with-param name="max-so-far"
select="string-length($input[1])" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="maxlen">
<xsl:with-param name="input" select="$input[position() > 1]" />
<xsl:with-param name="max-so-far" select="$max-so-far" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:variable name="input">
<test>
<string>123456789012345678901234</string>
<string>12345678901234</string>
<string>1234567890</string>
<string>12345678901234567890123456</string>
</test>
</xsl:variable>
<xsl:template match="/">
<output>
<xsl:call-template name="maxlen">
<xsl:with-param name="input" select="//test/string" />
</xsl:call-template>
</output>
</xsl:template>
</xsl:stylesheet>
这是如何使用 EXSLT math:max()
:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:math="http://exslt.org/math"
xmlns:str="http://exslt.org/strings">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/root">
<xsl:variable name="lengths">
<xsl:for-each select="data">
<length><xsl:value-of select="string-length(@a)"/></length>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="max_a_width" select="math:max(exsl:node-set($lengths)/length)"/>
<!-- the rest -->
</xsl:template>
</xsl:stylesheet>