如何使用XSLT在文本节点周围添加<p>标签</p>

时间:2014-02-06 11:01:45

标签: xml xslt

我有以下XML文档

<body>
  <h2>title</h2>
  some text and a <a href="link">link</a> here.
</body>

我想使用XSLT将其转换为:

<body>
  <h2>title</h2>
  <p>some text and a <a href="link">link</a> here.</p>
</body>

因此我尝试了以下XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" method="xml" cdata-section-elements="script"/>
  <xsl:template match="/ | node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="body/text()" >
    <p><xsl:copy/></p>
  </xsl:template>
</xsl:stylesheet>

但是这似乎没有给出预期的结果(如果文本节点不包含锚元素,它可以正常工作)。那么有关如何使用XSLT实现这一目标的任何想法? (我可以选择稍后使用C#解析XML,但我最初的想法是使用XSLT)

更新

为了使整体要求更加清晰,输入XML(或实际上是XHTML)不是固定的,它可以是用户输入的任何东西。我唯一可以期待的是,它将是有效的XML(XHTML)并且某些行可能不会包含在<p>标记中。

3 个答案:

答案 0 :(得分:1)

怎么样:

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

<xsl:template match="body">
    <xsl:copy>
        <xsl:apply-templates select=" @*|*[not(self::a)]"/>
        <p><xsl:copy-of select="text()|a"/></p>
    </xsl:copy>
</xsl:template>

答案 1 :(得分:1)

这比仅仅“在文本节点周围添加p标记稍微复杂一些”,因为在您的示例中,您实际上是尝试在一组三个节点周围添加一个p标记 - 两个文本节点和一个中间元素节点。对于您的具体示例,以下内容将起作用

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <body>
      <xsl:copy-of select="body/h2" />
      <p>
        <xsl:copy-of select="body/h2/following-sibling::node()" />         
      </p>
    </body>
  </xsl:template>
</xsl:stylesheet>

但这显然不是很通用。更一般地说,如果您想在一个h2中将所有内容包装在一个p和下一个key之间,那么您可以使用“Muenchian分组”方法的变体 - 使用h2关联每个非h2节点及其最近的前兄弟<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:key name="groupByHeader" match="node()[not(self::h2)]" use="generate-id(preceding-sibling::h2[1])" /> <xsl:template match="body"> <xsl:copy> <!-- everything before the first h2 --> <xsl:copy-of select="key('groupByHeader', '')" /> <xsl:apply-templates select="h2" /> </xsl:copy> </xsl:template> <xsl:template match="h2"> <!-- this h2 --> <xsl:copy-of select="."/> <!-- everything between this h2 and the next one (or the end of body) --> <p><xsl:copy-of select="key('groupByHeader', generate-id())" /></p> </xsl:template> </xsl:stylesheet>

<body><h2>title</h2><p>
  some text and a <a href="link">link</a> here.
</p></body>

在您的示例输入上,这两个样式表应该都产生相同的输出:

p

如果您需要缩进以精确匹配您的“预期输出”,那么它会变得更加毛茸茸,因为您基本上需要将第一个文本节点拆分为两个,将前导空格放在开始normalize-space()标记之前,其余的其后的文本节点,以及与最后一个文本节点类似的。你不能简单地<p>some text and a<a href="link">link</a>here.</p> 在每个文本节点上,因为这会剥离你需要保留的空间 - 你不想最终得到

{{1}}

答案 2 :(得分:-5)

试试这个:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" method="xml" cdata-section-elements="script"/>
  <xsl:template match="/ | node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="body" >
    <p><xsl:copy-of select="."/></p>
  </xsl:template>
</xsl:stylesheet>