XSLT:在specic标记处分解标记结构

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>

我使用XSLT2.0处理了一个XML文件,该文件可以包含一个附着于此DTD片段的标记

<!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[. &lt;&lt; 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

此…
提供此输出
foobar

zorkfieshfjkdashndk此
@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>