将模板应用于XSLT中的子字符串

时间:2015-07-22 22:18:31

标签: xml xslt substring apply-templates

想象一下,我的XML文件如下所示:

<root>
  <test>
    Lorem ipsum dolor sit amet, <randomTag>consectetur</randomTag>
    adipiscing elit, sed do <randomTag>eiusmod</randomTag> tempor
    incididunt ut labore et dolore magna aliqua...
  </test>
</root>

以下代码不起作用:

<xsl:template match="/">
  <xsl:apply-templates select="substring(test,1,50)"/> ...
</xsl:template>

<xsl:template match="randomTag">
  <myTag><xsl:value-of select="."/></myTag>
</xsl:template>

我期待以下输出:

Lorem ipsum dolor sit amet, <myTag>consectetur</myTag> 
adipiscing...

如果我用 test 替换 substring(test,1,50),它可以工作,但我只需要前50个字符。

我也尝试过以这种方式使用变量:

<xsl:template match="/">
  <xsl:variable name="aux" select="substring(test,1,50)"/>
  <xsl:apply-templates select="$aux"/> ...
</xsl:template>

但即便如此。

在我看来,问题是 substring()表达式。 一些建议?

3 个答案:

答案 0 :(得分:2)

<xsl:apply-templates>仅适用于node-set,即原始文档中的一组节点。

在许多XSLT处理器中,您可以使用exsl:node-set扩展功能创建其他node-set

答案 1 :(得分:1)

在XSLT 3.0之前,apply-templates必须选择节点(不是字符串或其他原子值),匹配模式只能匹配节点。 substring()函数提供一个字符串,并丢弃有关元素的任何信息。所以是的,substring()表达式就是问题所在。

那你怎么解决这个问题呢?答案是一种名为&#34;兄弟递归的技术&#34;。您将模板(通常以特定模式)应用于第一个子项,此模板对紧随其后的兄弟模板执行apply-templates。作为apply-templates的参数,您传递一个参数,指示何时停止(例如,最初将其设置为50,并在处理每个节点时减少字符数,当它达到零时,终止递归。)

答案 2 :(得分:0)

正如我在评论中已经提到的,如果要缩短的文本在子树的节点之间分割,那么这会变得复杂。它很复杂,因为 - 从概念上讲,至少 - XSLT并行处理树的分支,并且没有办法将信息从一个分支传递到下一个分支,就像你在进行循环时一样。

您可以采取两种可能的方法:

  • 强制样式表按顺序处理节点;
  • 让每个文本节点计算并行中发生的事情 按文档顺序排在当前分支之前的分支。

第二种选择似乎更容易,但效率非常低。这是一个通用的例子:

<强> XML

在本文档中,我插入了§作为每个项目正文的第100个字符。

<feed>
  <item>
    <title>Declaration</title>
    <body>
      <para>When in the Course of human events, it becomes necessary for one people to <bold>dissolve the political b§ands which have connected them with another</bold>, and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.</para>
      <para>We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness.</para>
    </body>
  </item>
  <item>
    <title>Lorem Isum</title>
    <body>
      <para>Lorem ipsum dolor sit amet consectetuer adipiscing elit. <bold>Nam interdum ante quis <italic>erat pellentesque e§lementum.</italic> Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</bold> Ut molestie quam sit amet ligula.</para>
      <para>In enim. Duis dapibus hendrerit quam. Donec hendrerit lectus vel nunc. Vestibulum sit amet pede nec neque dignissim vehicula.</para>
      <para>Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Phasellus eget ante. Quisque risus leo, dictum sit amet, nonummy sit amet, consectetuer ut, mi.</para>
    </body>
  </item>
  <item>
    <title>Subject</title>
    <body>
      <para>Subject to change without notice.</para>
      <para>Not responsible for direct, indirect, incidental or consequential §damages resulting from any defect, error or failure to perform.</para>
      <para>May be too intense for some viewers.</para>
    </body>
  </item>
</feed>

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="limit" select="100"/>

<xsl:template match="feed">
    <body>
        <xsl:apply-templates/>
    </body>
</xsl:template>

<xsl:template match="item">
    <h3><xsl:value-of select="title"/></h3>
    <xsl:apply-templates select="body"/>
    <hr/>
</xsl:template>

<xsl:template match="body">
    <p>
        <xsl:apply-templates mode="summary"/>
    </p>
</xsl:template>

<xsl:template match="bold" mode="summary">
    <b>
        <xsl:apply-templates mode="summary"/>
    </b>    
</xsl:template> 

<xsl:template match="italic" mode="summary">
    <i>
        <xsl:apply-templates mode="summary"/>
    </i>    
</xsl:template> 

<xsl:template match="text()" mode="summary">
    <xsl:variable name="text-before">
        <xsl:value-of select="ancestor::body//text()[current() >> .]" separator=""/>
    </xsl:variable>
    <xsl:variable name="used" select="string-length($text-before)" />   
    <xsl:if test="$used lt $limit">
        <xsl:value-of select="substring(., 1, $limit - $used)"/>
        <xsl:if test="string-length(.) + $used ge $limit">
            <xsl:text>...</xsl:text>
        </xsl:if>
    </xsl:if>
</xsl:template> 

</xsl:stylesheet>

<强>结果

<body>
   <h3>Declaration</h3>
   <p>When in the Course of human events, it becomes necessary for one people to <b>dissolve the political bß...</b>
   </p>
   <hr/>
   <h3>Lorem Isum</h3>
   <p>Lorem ipsum dolor sit amet consectetuer adipiscing elit. <b>Nam interdum ante quis <i>erat pellentesque e§...</i>
      </b>
   </p>
   <hr/>
   <h3>Subject</h3>
   <p>Subject to change without notice.Not responsible for direct, indirect, incidental or consequential ß...</p>
   <hr/>
</body>

<强>渲染

enter image description here

如您所见,每个项目在完全100个字符后被切断,同时保留内部层次结构,并且可以单独处理每种类型的节点。

注意:
在我写完这篇文章之后,我去看了你所链接的other question。接受的答案与此非常相似,但我相信我的更简单它会分别处理每个项目。