2

想象一下,我的 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()表达式。一些忠告?

4

3 回答 3

2

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

在许多 XSLT 处理器中,您可以node-set使用exsl:node-set扩展函数创建额外的。

于 2015-07-22T22:22:52.450 回答
1

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

那么你如何解决这个问题呢?答案是一种称为“兄弟递归”的技术。您将模板(通常以特定模式)应用于第一个孩子,并且此模板确实在紧随其后的兄弟姐妹上应用模板。作为应用模板的参数,您传递一个指示何时停止的参数(例如,最初将其设置为 50,并在处理每个节点时减少字符数,当它达到零时,终止递归。)

于 2015-07-22T23:02:06.950 回答
0

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

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

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

第二种选择似乎更容易,尽管它非常低效。这是一个通用示例:

XML

在本文档中,我插入了 a§作为每个项目正文的第 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>

渲染

在此处输入图像描述

如您所见,每个项目恰好在 100 个字符后被切断,而内部层次结构被保留,每种类型的节点都可以单独处理。


注意:
在我写完这个之后,我去看看你链接到的另一个问题。那里接受的答案与此非常相似,尽管我相信我的答案更简单一些,并且它分别处理每个项目。

于 2015-07-24T21:54:46.440 回答