[英]How do I use XSLT to merge XML elements and then structure elements/attributes of the same name/type?
主要问题
我有一个 XML 文件,其中包含多个相似的元素,但信息略有不同。 所以,假设我有两个 X 属性相同但 Y 属性不同的元素。 这是一个例子:
<FILE>
<ELEMENT>
<ATTRIBUTEX>1</ATTRIBUTEX>
<ATTRIBUTEY>A</ATTRIBUTEY>
</ELEMENT>
<ELEMENT>
<ATTRIBUTEX>1</ATTRIBUTEX>
<ATTRIBUTEY>B</ATTRIBUTEY>
</ELEMENT>
</FILE>
我想要做的是——基于两个元素具有相同的 X 属性这一事实——将它们合并为具有一个属性 X 和多个子元素(相同类型)的单个元素——每个元素都包含不同的属性 Y。因此,例如,我希望我的文件最终如下所示:
<FILE>
<ELEMENT>
<ATTRIBUTEX>1</ATTRIBUTEX>
<NEWELEMENT>
<ATTRIBUTEY>A</ATTRIBUTEY>
</NEWELEMENT>
<NEWELEMENT>
<ATTRIBUTEY>B</ATTRIBUTEY>
</NEWELEMENT>
</ELEMENT>
</FILE>
可能的解决方案?
我能想到的一种可能的解决方案,但缺乏执行知识,由两个步骤组成:
可能解决方案的问题
但是,一旦包含 X 属性的所有元素都合并在一起(第一步),我将有一个文件,其中将有同名的属性(特别是 Y 属性)。 这是一个例子:
<FILE>
<ELEMENT>
<ATTRIBUTEX>1</ATTRIBUTEX>
<ATTRIBUTEY>A</ATTRIBUTEY>
<ATTRIBUTEY>B</ATTRIBUTEY>
</ELEMENT>
</FILE>
这意味着 - 至少据我所知 - 当我在上述 XML (第二步)上执行 XSLT 文件时,在将两个 Y 元素排序到两个新的子元素( NEWELEMENT
)时,它无法区分它们。
所以,假设我在上面的 XML 上执行了下面的 XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="FILE">
<Record>
<xsl:for-each select = "ELEMENT">
<ELEMENT>
<xsl:copy-of select="ATTRIBUTEX"/>
<NEWELEMENT>
<xsl:copy-of select="ATTRIBUTEY"/>
</NEWELEMENT>
<NEWELEMENT>
<xsl:copy-of select="ATTRIBUTEY"/>
</NEWELEMENT>
</ELEMENT>
</xsl:for-each>
</Record>
</xsl:template>
</xsl:stylesheet>
output 是这样的:
<Record>
<ELEMENT>
<ATTRIBUTEX>1</ATTRIBUTEX>
<NEWELEMENT>
<ATTRIBUTEY>A</ATTRIBUTEY>
<ATTRIBUTEY>B</ATTRIBUTEY>
</NEWELEMENT>
<NEWELEMENT>
<ATTRIBUTEY>A</ATTRIBUTEY>
<ATTRIBUTEY>B</ATTRIBUTEY>
</NEWELEMENT>
</ELEMENT>
</Record>
如您所见, NEWELEMENT
已将所有和任何ATTRIBUTEY
元素放入每个新元素中,而不是区分它们并将一个ATTRIBUTEY
放在第一个NEWELEMENT
中,将第二个ATTRIBUTEY
放在第二个NEWELEMENT
中。 我需要一个 XSLT 文件来执行此操作,并且如前所述,生成一个看起来像这样的 XML :
<FILE>
<ELEMENT>
<ATTRIBUTEX>1</ATTRIBUTEX>
<NEWELEMENT>
<ATTRIBUTEY>A</ATTRIBUTEY>
</NEWELEMENT>
<NEWELEMENT>
<ATTRIBUTEY>B</ATTRIBUTEY>
</NEWELEMENT>
</ELEMENT>
</FILE>
有人能帮我解决这个问题吗? 任何从第一个示例文件生成所需 output(上图)的解决方案都将不胜感激。 如果该解决方案遵循第一步和第二步,那将是一个奖励。 谢谢!
我正在从下面的 XSLT 3.0 中获得您请求的 output。
只是事先说明几点:
尽管如此,作为样式(表)的练习,这里有一个样式表,它从您的给定输入生成您的 output:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes" />
<xsl:template match="/FILE" >
<FILE>
<xsl:for-each-group select="*" group-by="name(.)" >
<xsl:variable name="parentName" as="xs:string" select="current-grouping-key()" />
<xsl:variable name="childNamesSameValues" as="xs:string*" >
<xsl:for-each-group select="current-group()/*" group-by="name(.)" >
<xsl:if test="count(distinct-values(current-group()/text())) eq 1">
<xsl:sequence select="current-grouping-key()" />
</xsl:if>
</xsl:for-each-group>
</xsl:variable>
<xsl:element name="{$parentName}" >
<xsl:for-each-group select="current-group()/*" group-by="name(.)" >
<xsl:choose>
<xsl:when test="current-grouping-key() = $childNamesSameValues">
<xsl:copy-of select="current-group()[1]" />
</xsl:when>
<xsl:otherwise >
<xsl:for-each select="current-group()" >
<xsl:element name="NEW{$parentName}" >
<xsl:copy-of select="." />
</xsl:element>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:element>
</xsl:for-each-group>
</FILE>
</xsl:template>
</xsl:stylesheet>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.