修剪HTML锚点节点中的href

时间:2013-02-05 22:37:26

标签: xml xslt xslt-1.0

嘿我需要使用XML 1.0将每个<a>标记内的内容修剪为描述节点中的字符限制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”&lt; a&gt;。

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

**编辑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>

问题是“apply-templates”不起作用,因为我的XSL中有多个模板。我需要专门调用一个模板,所以我假设“call-template”将是要走的路。 “call-template”的唯一问题是我不知道如何指定要引用的特定XML节点。以下是我到目前为止的攻击方式(deos not working):

    <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>

最初的'调用模板'需要在<xsl:template match="/">中,因为这是一个更大的功能。所以我需要3件事:

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

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

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

3 个答案:

答案 0 :(得分: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. Identity rule - 按照选择执行此模板的每个节点进行复制。

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

答案 1 :(得分: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,而是使用模板规则和apply-templates。你可以在哪里使用模板。

答案 2 :(得分:1)

  

问题是“apply-templates”不起作用,因为我的XSL中有多个模板。我需要专门调用一个模板,所以我假设“call-template”将是要走的路。 “call-template”的唯一问题是我不知道如何指定要引用的特定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>

(因为“这是一个”和“非常”已经短于20个字符,而“长文本”是截断为“用作...的长文本”的20个字符。)