2

嘿,我需要<a>使用 XML 1.0 将每个标记中的内容修剪到描述节点中的字符限制 20。这是XML

  <description> 
       This is text <a href="http://stackoverflow.com/posts/14718323/edit">http://stackoverflow.com/posts/14718323/edit</a>. 
       Also here is more text than we have another 
       <a href="http://stackoverflow.com/posts/14718323/edit">http://stackoverflow.com/posts/14718323/edit</a>.
  </description>

我需要它变成这样:

  <description> 
       This is text <a href="http://stackoverflow.com/posts/14718323/edit">http://stacko</a>. 
       Also here is more text than we have another 
       <a href="http://stackoverflow.com/posts/14718323/edit">http://stacko</a>.
  </description>

我可以做大部分的逻辑,但我在做一个“for-each”搜索描述节点并转换“each”<a>时遇到了麻烦。

这有意义吗?任何帮助表示赞赏。

** 编辑 2/7/13 *

根据这里提供的答案是我现在的位置。

   <xsl:template match="/">
     <xsl:apply-templates select="//description"/>
   </xsl:template>

   <xsl:template match="a">
    <a href="{@href}">
       <xsl:value-of select="substring(normalize-space(),1,20)"/>
    </a>
   </xsl:template>

问题是“应用模板”不起作用,因为我的 XSL 中有多个模板。我需要专门调用一个模板,所以我认为“调用模板”将是要走的路线。“调用模板”的唯一问题是我不知道如何指定要引用的特定 XML 节点。到目前为止,这是我如何破解它(deosn't work):

    <xsl:template match="/">
      <xsl:call-template name="trim_text"/>
     </xsl:template>

    <xsl:template name="trim_text" match="//description">
     <a href="{@href}">
       <xsl:value-of select="substring(normalize-space(),1,20)"/>
     </a>
    </xsl:template>

最初的“调用模板”需要在 a 中,<xsl:template match="/">因为这是在一个更大的函数中。所以我需要三样东西:

1) HREF 与 XML 中的内容保持一致

2)标签之间的文字<a>要修剪到20px

3) 我需要从一个更大的 xsl 模板中调用这个模板,该模板对 XML 做了很多转换。这将是大约 7 个模板调用。

4

3 回答 3

2

这种转换避免了使用xsl:attribute, 格式更好,可读性更好

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

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="a[@href]">
  <a href="{substring(@href,1,20)}">
    <xsl:apply-templates select="@*[not(name()='href')]|node()"/>
  </a>
 </xsl:template>
</xsl:stylesheet>

应用于此 XML 文档时:

<root>
    <description>
            This is text 
        <a href="http://www.longlink/morelink/page/anotherpage">Link Here</a>.
            Also here is more text than we have another
        <a href="link-style:null">Link Here</a>.
    </description>
</root>

产生想要的正确结果:

<root>
   <description>
            This is text 
        <a href="http://www.longlink/">Link Here</a>.
            Also here is more text than we have another
        <a href="link-style:null">Link Here</a>.
    </description>
</root>

说明

  1. 身份规则——按原样复制选择此模板执行的每个节点。

  2. 使用AVT(属性值模板)。

于 2013-02-06T03:42:51.967 回答
1

问题是“应用模板”不起作用,因为我的 XSL 中有多个模板。我需要专门调用一个模板,所以我认为“调用模板”将是要走的路线。“调用模板”的唯一问题是我不知道如何指定要引用的特定 XML 节点。

模板模式可能是您正在寻找的

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="/">
    <!-- do some other stuff ... -->

    <!-- handle the description -->
    <xsl:apply-templates select=".//description" mode="description" />

    <!-- more other stuff here -->
  </xsl:template>

  <!-- description-specific templates -->
  <xsl:template match="@* | node()" mode="description">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" mode="description" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="a" mode="description">
    <xsl:copy>
      <xsl:apply-templates select="@*" mode="description" />
      <xsl:value-of select="substring(., 1, 20)" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

当您使用 指定模式时apply-templates,在查找要应用于每个节点的模板时,仅考虑标记为相同模式的模板(加上匹配所有元素节点并递归地将模板应用于使用相同模式的子节点的默认隐式模板,但是这不适用于这里,因为我们有一个身份模板)。例如,此元素的示例模板a不允许包含其他标签的链接

<a href="#">This is a <b>very</b> long piece of text used as an example</a>

会成为

<a href="#">This is a very long </a>

如果你想保留这样的标记,它会变得更加复杂。你不能用明显的方法来做到这一点

<xsl:template match="a//text()" mode="description">
  <xsl:value-of select="substring(., 1, 20)"/>
</xsl:template>

因为这将孤立地对待每个文本节点,并产生

<a href="#">This is a <b>very</b> long piece of text </a>

(因为“This is a”和“very”已经短于20个字符,而“long-piece of text”是“long-piece of text used as...”截断到20个字符)

于 2013-02-07T16:00:19.287 回答
1

回答 OP 评论中修订的问题,即他需要将字符限制为 20 个字符。

尝试使用 substring 函数只返回前 20 个字符:

<xsl:value-of select="substring(.,1,20)"/>

这是一个更完整的答案:

这个 XSLT 1.0 转换:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>  
        </xsl:template>
        <xsl:template match="a/@href">
            <xsl:attribute name="href"><xsl:value-of select="substring(.,1,20)"/></xsl:attribute>
        </xsl:template>
    </xsl:stylesheet>

应用于此 XML 文档时:

    <root>
        <description> 
            This is text <a href="http://www.longlink/morelink/page/anotherpage">Link Here</a>. 
            Also here is more text than we have another 
            <a href="link-style:null">Link Here</a>.
        </description>
    </root>

产生所需的结果(注意第一个 href 属性的缩短):

    <root>
        <description> 
            This is text <a href="http://www.longlink/">Link Here</a>. 
            Also here is more text than we have another 
            <a href="link-style:null">Link Here</a>.
        </description>
    </root>

解释:

  • 恒等变换(第一个模板)会将所有节点和属性复制到结果树,
  • 第二个模板将仅复制 href 的前 20 个字符
  • 还要注意缺少 for-each,而是使用模板规则和应用模板。在可能的情况下,您应该使用模板。
于 2013-02-05T23:55:42.140 回答