我有以下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>
标记中。
答案 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>