将XSLT节点集B插入到节点集A的文本节点内检测到的位置处的另一个节点集A.

时间:2011-10-18 19:29:07

标签: xslt

我正在使用XSLT将内容管理系统的复杂XML输出转换为XHTML。我正在使用<xsl:apply-templates/>来获取XML输入描述的XHTML片段。 XML输入带有一个非常复杂的结构,可以描述许多不同的情况,由几个XSLT模板元素处理。而且这种结构将来可能会经常发生变化。

以前,该转换的结果片段直接发送到XSLT输出。现在需求已经改变,我需要捕获结果,偶尔修改它以在片段的值的某个位置插入一些其他格式良好的XHTML片段。

为了演示,请考虑<xsl:apply-templates/>创建了一些在变量容器中捕获的不透明XHTML片段。

<xsl:variable name="container">
  <xsl:apply-templates />
</xsl:variable>

接下来,在变量代码段中有第二个XHTML片段:

<xsl:variable name="snippet">
  <xsl:call-template name="get-snippet" />
</xsl:variable>

要求说要在 $ snippet 中的节点设置插入 $ container 的值结尾之前的任何可选包含句点之前插入。除非必须将两个变量中的XHTML片段保持为片段,否则这不成问题。因此,无法对任一变量的字符串值进行操作。

是否有机会在XSLT中实现该要求而不会失去<xsl:apply-templates/> $ container 中检索XHTML片段的能力和灵活性?

BTW:我已经知道使用以下方法访问$container中的最后一个文本节点

node-set($container)//child::text[last()] 

但我错过了在该文本节点的中间插入一些东西,我认为XSLT无法为我想要做的事情提供适当的支持。

1 个答案:

答案 0 :(得分:2)

<强>予。 XSLT 1.0解决方案:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 exclude-result-prefixes="ext">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vrtfContainer">
  <html>
   <p>Hello, world.</p>
   <p> This is <b>just</b> a <i>demo.</i></p>
   <p> Of some text</p>
  </html>
 </xsl:variable>

 <xsl:variable name="vContainer" select=
  "ext:node-set($vrtfContainer)/*"/>

 <xsl:variable name="vrtfSnippet">
   <p>Snippet</p>
 </xsl:variable>

 <xsl:variable name="vSnippet" select=
  "ext:node-set($vrtfSnippet)/*"/>

  <xsl:variable name="vText" select=
  "($vContainer//text()[contains(.,'.')])[last()]"/>

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

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

 <xsl:template match="text()">
  <xsl:choose>
   <xsl:when test="not(generate-id() = generate-id($vText))">
    <xsl:value-of select="."/>
   </xsl:when>
   <xsl:otherwise>
     <xsl:call-template name="insertSnippet">
      <xsl:with-param name="pText" select="$vText"/>
     </xsl:call-template>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

 <xsl:template name="insertSnippet">
  <xsl:param name="pText"/>

    <xsl:copy-of select="substring-before($pText, '.')"/>

    <xsl:variable name="vTail" select=
         "substring-after($pText, '.')"/>

  <xsl:choose>
   <xsl:when test="not(contains(substring($vTail,2), '.'))">
    <xsl:copy-of select="$vSnippet"/>
    <xsl:value-of select="concat('.', $vTail)"/>
   </xsl:when>
   <xsl:otherwise>
    <xsl:text>.</xsl:text>
    <xsl:call-template name="insertSnippet">
     <xsl:with-param name="pText"
      select="substring-after($pText, '.')"/>
    </xsl:call-template>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

当应用此转换时(对任何XML文档 - 未使用),将生成所需的正确结果

<html>
   <p>Hello, world.</p>
   <p> This is <b>just</b> a <i>demo
         <p>Snippet</p>.</i></p>
   <p> Of some text</p>
</html>

解释:身份规则由递归命名模板覆盖,以查找字符串中的最后一个'.'


<强> II。 XSLT 2.0解决方案:

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

 <xsl:variable name="vContainer">
  <html>
   <p>Hello, world.</p>
   <p> This is <b>just</b> a <i>demo.</i></p>
   <p> Of some text</p>
  </html>
 </xsl:variable>


 <xsl:variable name="vSnippet">
   <p>Snippet</p>
 </xsl:variable>

  <xsl:variable name="vText" select=
  "($vContainer//text()[contains(.,'.')])[last()]"/>

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

 <xsl:template match="/">
  <xsl:apply-templates select="$vContainer/*"/>
 </xsl:template>

 <xsl:template match="text()[. is $vText]">
  <xsl:variable name="vInd" select=
   "index-of(string-to-codepoints(.), string-to-codepoints('.'))[last()]"/>
  <xsl:sequence select="substring(., 1, $vInd -1)"/>
  <xsl:sequence select="$vSnippet/*"/>
  <xsl:sequence select="substring(., $vInd)"></xsl:sequence>
 </xsl:template>
</xsl:stylesheet>

执行此XSLT 2.0转换后,再次生成所需的正确结果

<html>
   <p>Hello, world.</p>
   <p> This is <b>just</b> a <i>demo
         <p>Snippet</p>.</i></p>
   <p> Of some text</p>
</html>

解释:使用标准XPath 2.0函数string-to-codepoints()index-of()substring()和运算符is