使用 XSLT 拆分重复文本()并将非重复文本分组在一起
Using XSLT to split duplicate text() and group non-duplicates together
我有以下输入 XML:
<root>
<element>
<id>1</id>
<text><![CDATA[My text 1]]></text>
</element>
<element>
<id>2</id>
<text><![CDATA[My text 1]]></text>
</element>
<element>
<id>3</id>
<text><![CDATA[My text 2]]></text>
</element>
<element>
<id>4</id>
<text><![CDATA[My text 2]]></text>
</element>
<element>
<id>5</id>
<text><![CDATA[My text 3]]></text>
</element>
</root>
我希望使用 XSLT 2.0 对此进行转换,以拆分文本元素中的重复 text() 并将我的非重复项分组到单独的文件中(对于任意数量的重复项 - 我的例子只显示了两个)。所以我的任何输出文件中都不应该有重复的 text() ,并且需要将它们分组到尽可能少的文件中。我上面的输出应该是这样的:
document1.xml
<root>
<element>
<id>1</id>
<text><![CDATA[My text 1]]></text>
</element>
<element>
<id>3</id>
<text><![CDATA[My text 2]]></text>
</element>
<element>
<id>5</id>
<text><![CDATA[My text 3]]></text>
</element>
</root>
document2.xml
<root>
<element>
<id>2</id>
<text><![CDATA[My text 1]]></text>
</element>
<element>
<id>4</id>
<text><![CDATA[My text 2]]></text>
</element>
</root>
我现有的 XSLT 片段如下所示:我觉得我需要在我的 for-each-group 中收集重复项(以便按位置拆分),但显然这会导致每个元素一个文件:
<xsl:for-each-group select="descendant::element" group-by="text[text() = preceding::text/text() or text() = following::text/text()]">
<xsl:result-document href="{concat($outputdir,'\document',position(),'.xml')}" method="xml" indent="yes" cdata-section-elements="text">
<root>
<xsl:copy-of select="."/>
</root>
</xsl:result-document>
</xsl:for-each-group>
感谢您提供的任何帮助。提前致谢。
以下看起来更像是使用 XSLT 完成的命令式解决方案,但我认为它可以完成工作:
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:template match="root">
<xsl:variable name="groups">
<xsl:for-each-group select="element" group-by="text">
<group key="{current-grouping-key()}">
<xsl:copy-of select="current-group()"/>
</group>
</xsl:for-each-group>
</xsl:variable>
<xsl:variable name="max-size" select="max($groups/group/count(element))"/>
<xsl:for-each select="1 to $max-size">
<xsl:result-document href="document{.}.xml">
<root>
<xsl:copy-of select="$groups/group/element[position() eq current()]"/>
</root>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root">
<xsl:call-template name="out">
<xsl:with-param name="level" select="1"/>
<xsl:with-param name="root" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="out">
<xsl:param name="root"/>
<xsl:param name="level"/>
<xsl:if test="$root/*">
<xsl:result-document href="document{$level}.xml">
<root>
<xsl:for-each-group select="$root/*" group-by="text">
<xsl:copy-of select="current()"/>
</xsl:for-each-group>
</root>
</xsl:result-document>
<xsl:call-template name="out">
<xsl:with-param name="level" select="$level+1"/>
<xsl:with-param name="root">
<xsl:for-each-group select="$root/*" group-by="text">
<xsl:copy-of select="current-group()[. != current()]"/>
</xsl:for-each-group>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
我有以下输入 XML:
<root>
<element>
<id>1</id>
<text><![CDATA[My text 1]]></text>
</element>
<element>
<id>2</id>
<text><![CDATA[My text 1]]></text>
</element>
<element>
<id>3</id>
<text><![CDATA[My text 2]]></text>
</element>
<element>
<id>4</id>
<text><![CDATA[My text 2]]></text>
</element>
<element>
<id>5</id>
<text><![CDATA[My text 3]]></text>
</element>
</root>
我希望使用 XSLT 2.0 对此进行转换,以拆分文本元素中的重复 text() 并将我的非重复项分组到单独的文件中(对于任意数量的重复项 - 我的例子只显示了两个)。所以我的任何输出文件中都不应该有重复的 text() ,并且需要将它们分组到尽可能少的文件中。我上面的输出应该是这样的:
document1.xml
<root>
<element>
<id>1</id>
<text><![CDATA[My text 1]]></text>
</element>
<element>
<id>3</id>
<text><![CDATA[My text 2]]></text>
</element>
<element>
<id>5</id>
<text><![CDATA[My text 3]]></text>
</element>
</root>
document2.xml
<root>
<element>
<id>2</id>
<text><![CDATA[My text 1]]></text>
</element>
<element>
<id>4</id>
<text><![CDATA[My text 2]]></text>
</element>
</root>
我现有的 XSLT 片段如下所示:我觉得我需要在我的 for-each-group 中收集重复项(以便按位置拆分),但显然这会导致每个元素一个文件:
<xsl:for-each-group select="descendant::element" group-by="text[text() = preceding::text/text() or text() = following::text/text()]">
<xsl:result-document href="{concat($outputdir,'\document',position(),'.xml')}" method="xml" indent="yes" cdata-section-elements="text">
<root>
<xsl:copy-of select="."/>
</root>
</xsl:result-document>
</xsl:for-each-group>
感谢您提供的任何帮助。提前致谢。
以下看起来更像是使用 XSLT 完成的命令式解决方案,但我认为它可以完成工作:
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:template match="root">
<xsl:variable name="groups">
<xsl:for-each-group select="element" group-by="text">
<group key="{current-grouping-key()}">
<xsl:copy-of select="current-group()"/>
</group>
</xsl:for-each-group>
</xsl:variable>
<xsl:variable name="max-size" select="max($groups/group/count(element))"/>
<xsl:for-each select="1 to $max-size">
<xsl:result-document href="document{.}.xml">
<root>
<xsl:copy-of select="$groups/group/element[position() eq current()]"/>
</root>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root">
<xsl:call-template name="out">
<xsl:with-param name="level" select="1"/>
<xsl:with-param name="root" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="out">
<xsl:param name="root"/>
<xsl:param name="level"/>
<xsl:if test="$root/*">
<xsl:result-document href="document{$level}.xml">
<root>
<xsl:for-each-group select="$root/*" group-by="text">
<xsl:copy-of select="current()"/>
</xsl:for-each-group>
</root>
</xsl:result-document>
<xsl:call-template name="out">
<xsl:with-param name="level" select="$level+1"/>
<xsl:with-param name="root">
<xsl:for-each-group select="$root/*" group-by="text">
<xsl:copy-of select="current-group()[. != current()]"/>
</xsl:for-each-group>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>