【问题标题】:How to calculate max string-length of a node-set?如何计算节点集的最大字符串长度?
【发布时间】:2015-09-07 11:55:37
【问题描述】:

我正在尝试使用 XSLT 将 XML 文档转换为纯文本表格以供人类使用。我正在使用 xsltproc,它只实现 XSLT 1.0(所以 max 实际上来自 EXSLT)。

我尝试了以下方法,但注释掉的定义失败了,因为 string-length 只返回一个值(first 节点的字符串值的长度),而不是像 @987654324 这样的节点集@想要。

转换:

<?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>-+&#10;</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> |&#10;</xsl:text>
    </xsl:for-each>
    <xsl:text>+-</xsl:text><xsl:value-of select="str:padding($max_a_width, '-')"/><xsl:text>-+&#10;</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  |
+----+

为了使右边框对齐,我需要在变量中设置实际的最大值。 (在我的真实示例中,我将有列标题和多个列,但它们不是重现问题所必需的)。

如果它更容易找到解决方案,我可以保证数据值永远不会包含空格。

【问题讨论】:

    标签: xml xslt xslt-1.0 libxslt


    【解决方案1】:
    <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 中从派生值的有序列表中挑选的一般方法。

    如果您想从实际(本机可排序)值中选择最小值/最大值,您可以走捷径:

    <xsl:variable name="max_a" select="//a[not(. &lt; //a)][1]" />
    

    【讨论】:

      【解决方案2】:

      这是如何使用 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>
      

      【讨论】:

        【解决方案3】:

        这是一个简单的递归模板。使用相同的 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]) &gt; $max-so-far">
                <xsl:call-template name="maxlen">
                  <xsl:with-param name="input" select="$input[position() &gt; 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() &gt; 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>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-07
          • 1970-01-01
          • 2017-12-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多