XSLT:在specic标记处分解标记结构
我使用XSLT2.0处理了一个XML文件,该文件可以包含一个附着于此DTD片段的标记XSLT:在specic标记处分解标记结构,xslt,Xslt,我使用XSLT2.0处理了一个XML文件,该文件可以包含一个附着于此DTD片段的标记 <!ELEMENT p (#PCDATA|foo|bar|table)* > 也就是说,只要找到-tag,就“拆分”-tag,然后继续执行(如果还剩下任何子项) 请注意,这也是一个有效的输入示例 <p><table attr1="a" attr2="b">...</table></p> <p>bbbb<foo>
<!ELEMENT p (#PCDATA|foo|bar|table)* >
也就是说,只要找到
-tag,就“拆分”
-tag,然后继续执行
(如果还剩下任何子项)
请注意,这也是一个有效的输入示例
<p><table attr1="a" attr2="b">...</table></p>
<p>bbbb<foo>aaaa</foo></p>
应该转换成
<table attr1="a" attr2="b">...</table>
。。。
这也是一个有效的输入示例
<p><table attr1="a" attr2="b">...</table></p>
<p>bbbb<foo>aaaa</foo></p>
bbaaaa
它根本不应该被转换,也就是说输出应该是
<p>bbbb<foo>aaaa</foo></p>
bbaaaa
到目前为止,我使用的XSLT包括以下内容
<xsl:template match="p[table]">
<xsl:call-template name="split-paragraph">
<xsl:with-param name="tables" select="table"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="split-paragraph">
<xsl:param name="tables"/>
<xsl:if test="$tables">
<xsl:for-each select="$tables[1]">
<xsl:if test="not(preceding-sibling::node//table)">
<p><xsl:apply-templates select="preceding-sibling::node()[not(table)]"/></p>
</xsl:if>
<xsl:apply-templates select="."/>
<xsl:if test="not(following-sibling::node()//table)">
<p><xsl:apply-templates select="following-sibling::node[. << following-sibling::node()[not(name()='table')][1]]"/></p>
</xsl:if>
<xsl:call-template name="split-paragraph">
<xsl:with-param name="tables"
select="$tables[position() > 1]"/>
</xsl:call-template>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template match="table">
<xsl:element name="table">
<xsl:apply-templates select="attribute()"/>
<xsl:apply-templates select="node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="element()"><xsl:copy/></xsl:template>
适用于
<p>foo
<table attr1="gazonk"><a>bar</a></table>
<bar>xyzzy</bar>
<table attr2="2"><b>fie</b></table>
shfjkdashndk
</p>
foo
酒吧
xyzzy
五
shfjkdashndk
产生
<p>foo</p>
<table attr1="gazonk">
<a>bar</a>
</table>
<p>
</p>
<p>foo
<table attr1="gazonk">
<a>bar</a>
</table>
<bar>xyzzy</bar>
</p>
<table attr2="2">
<b>fie</b>
</table>
<p>shfjkdashndk</p>
foo
酒吧
福
酒吧
xyzzy
五
shfjkdashndk
这不是期望的输出。我想要这个
<p>foo</p>
<table attr1="gazonk">
<a>bar</a>
</table>
<p><bar>xyzzy</bar></p>
<table attr2="2">
<b>fie</b>
</table>
<p>shfjkdashndk</p>
foo
酒吧
xyzzy
五
shfjkdashndk
尝试以下样式表:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[table]/child::text()">
<p><xsl:value-of select="normalize-space(.)"/></p>
</xsl:template>
<xsl:template match="p[table]/*[not(self::table)]">
<p>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</p>
</xsl:template>
<xsl:template match="p[table]">
<xsl:apply-templates select="node()|@*"/>
</xsl:template>
</xsl:stylesheet>
如果您使用的是XSLT 1.0,则可以将其视为分组问题。您不是在将表元素分组在一起,而是在要分组的节点之前的表元素数量上进行分组。使用,您可以这样定义一个键
<xsl:key name="group" match="p/node()[not(self::table)]" use="concat(generate-id(..), '-', count(preceding-sibling::table))" />
您需要一个模板来匹配每个组中出现的第一个非表元素,这样您就可以在其周围添加p标记以及组中的其他项,如下所示
<xsl:template match="node()[generate-id() = generate-id(key('group', concat(generate-id(..), '-', count(preceding-sibling::table)))[1])]" mode="group">
<p>
<xsl:apply-templates select="key('group', concat(generate-id(..), '-', count(preceding-sibling::table)))"/>
</p>
</xsl:template>
编辑2.0
这里是XSLT2.0解决方案,您可以使用xsl:for each group对元素进行分组。在本例中,我将相邻元素分组在一起,这取决于它们是否是表
也不是在检查名称空间时使用通配符(这将处理是否存在名称空间)
您在这里使用的是XSLT 1.0还是XSLT 2.0?XSLT 2.0(以及Saxon 9 HE)。这“几乎”有效。每个元素都被包装在一个标签中:(我将更新示例以更好地显示所需的结果。这“几乎”起作用(我使用的是XSLT 2.0)。唉,它给出了xmlns=“”(由于使用了复制构造,但我猜使用显式创建很容易修复。)更重要的是,文本节点根本不会被包装(此输入…foobarxyzyzorkfieshfjkdashndk此…
提供此输出foobarzorkfieshfjkdashndk此
@3721979我对我的答案进行了编辑,以显示如何保留名称空间。谢谢@Tim。是否也可以通过一些简单的编辑来解决文本节点问题?这不是文本的问题des位于-tags中(并且序列中的所有非表标记都需要共享相同的-tag)…如果我从p
标记的创建中删除名称空间=“{namespace uri(..)}
,此解决方案有效!)但是有人能告诉我如何使用XSLT2.0原语简化Muenchian分组吗?我已经修改了我的答案,以显示XSLT2.0解决方案。
<xsl:template match="node()[generate-id() = generate-id(key('group', concat(generate-id(..), '-', count(preceding-sibling::table)))[1])]" mode="group">
<p>
<xsl:apply-templates select="key('group', concat(generate-id(..), '-', count(preceding-sibling::table)))"/>
</p>
</xsl:template>
<xsl:template match="table" mode="group">
<xsl:apply-templates select="." />
</xsl:template>
<xsl:template match="node()" mode="group" />
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="group" match="p/node()[not(self::table)]" use="concat(generate-id(..), '-', count(preceding-sibling::table))" />
<xsl:template match="p">
<xsl:apply-templates mode="group" />
</xsl:template>
<xsl:template match="node()[generate-id() = generate-id(key('group', concat(generate-id(..), '-', count(preceding-sibling::table)))[1])]" mode="group">
<p>
<xsl:apply-templates select="key('group', concat(generate-id(..), '-', count(preceding-sibling::table)))"/>
</p>
</xsl:template>
<xsl:template match="table" mode="group">
<xsl:apply-templates select="." />
</xsl:template>
<xsl:template match="node()" mode="group" />
<xsl:template match="@*|node()" >
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="group" match="*[local-name() = 'p']/node()[not(self::*[local-name() = 'table'])]" use="concat(generate-id(..), '-', count(preceding-sibling::*[local-name() = 'table']))" />
<xsl:template match="*[local-name() = 'p']">
<xsl:apply-templates mode="group" />
</xsl:template>
<xsl:template match="node()[generate-id() = generate-id(key('group', concat(generate-id(..), '-', count(preceding-sibling::*[local-name() = 'table'])))[1])]" mode="group">
<xsl:element name="p" namespace="{namespace-uri(..)}">
<xsl:apply-templates select="key('group', concat(generate-id(..), '-', count(preceding-sibling::*[local-name() = 'table'])))"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[local-name() = 'table']" mode="group">
<xsl:apply-templates select="." />
</xsl:template>
<xsl:template match="node()" mode="group" />
<xsl:template match="@*|node()" >
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*:p">
<xsl:for-each-group select="node()" group-adjacent="boolean(self::*:table)">
<xsl:choose>
<xsl:when test="self::*:table">
<xsl:apply-templates select="current-group()" />
</xsl:when>
<xsl:otherwise>
<xsl:element name="p" namespace="{namespace-uri(..)}">
<xsl:apply-templates select="current-group()" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="@*|node()" >
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>