我想使用XSLT 1.0将其中一个xmls转换为主详细信息格式。我试图通过这里的一些帖子获得见解,但无法做到正确。这里MsgID和PartID形成唯一键。
源XML:
<Parts>
<Part>
<MsgID>ABNHH877JJ</MsgID>
<PartID>10</PartID>
<Attr1>Part10-Attr1</Attr1>
<Attr2>Part10-Attr2</Attr2>
</Part>
<Part>
<MsgID>ABNHH877JJIUJ1</MsgID>
<PartID>10</PartID>
<Attr1>Part10-I-Attr1</Attr1>
<Attr2>Part10-I-Attr2</Attr2>
</Part>
<Part>
<MsgID>ABNHH877JJGHJ</MsgID>
<PartID>20</PartID>
<Attr1>Part20-Attr1</Attr1>
<Attr2>Part20-Attr2</Attr2>
</Part>
</Parts>
必需的目标XML:
<Parts>
<Part>
<MsgID>ABNHH877JJ</MsgID>
<PartID>10</PartID>
<Attrs>
<Attr1>Part10-Attr1</Attr1>
<Attr2>Part10-Attr2</Attr2>
</Attrs>
<Attrs>
<Attr1>Part10-I-Attr1</Attr1>
<Attr2>Part10-I-Attr2</Attr2>
</Attrs>
</Part>
<Part>
<MsgID>ABNHH877JJGHJ</MsgID>
<PartID>20</PartID>
<Attrs>
<Attr1>Part20-Attr1</Attr1>
<Attr2>Part20-Attr2</Attr2>
</Attrs>
</Part>
</Parts>
答案 0 :(得分:2)
更正了XML:
<?xml version="1.0" encoding="utf-8"?>
<Parts>
<Part>
<MsgID>ABNHH877JJ</MsgID>
<PartID>10</PartID>
<Attr1>Part10-Attr1</Attr1>
<Attr2>Part10-Attr2</Attr2>
</Part>
<Part>
<MsgID>ABNHH877JJ</MsgID>
<PartID>10</PartID>
<Attr1>Part10-I-Attr1</Attr1>
<Attr2>Part10-I-Attr2</Attr2>
</Part>
<Part>
<MsgID>ABNHH877JJGHJ</MsgID>
<PartID>20</PartID>
<Attr1>Part20-Attr1</Attr1>
<Attr2>Part20-Attr2</Attr2>
</Part>
</Parts>
XSLT代码:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/Parts/Part">
<xsl:copy>
<xsl:apply-templates select="MsgID|PartID"/>
<xsl:element name="Attrs">
<xsl:apply-templates select="Attr1|Attr2"/>
</xsl:element>
<xsl:for-each select="following-sibling::Part[MsgID= current()/MsgID and PartID= current()/PartID]">
<xsl:element name="Attrs">
<xsl:apply-templates select="Attr1|Attr2"/>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="/Parts/Part[MsgID = preceding-sibling::Part/MsgID and PartID = preceding-sibling::Part/PartID]"/>
</xsl:stylesheet>
结果:
<?xml version="1.0" encoding="utf-8"?>
<Parts>
<Part>
<MsgID>ABNHH877JJ</MsgID>
<Attrs>
<Attr1>Part10-Attr1</Attr1>
<Attr2>Part10-Attr2</Attr2>
</Attrs>
<Attrs>
<Attr1>Part10-I-Attr1</Attr1>
<Attr2>Part10-I-Attr2</Attr2>
</Attrs>
</Part>
<Part>
<MsgID>ABNHH877JJGHJ</MsgID>
<Attrs>
<Attr1>Part20-Attr1</Attr1>
<Attr2>Part20-Attr2</Attr2>
</Attrs>
</Part>
</Parts>
答案 1 :(得分:2)
正确的,简短而有效的XSLT 1.0解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPartById" match="Part" use="PartID"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Part[generate-id()=generate-id(key('kPartById', PartID)[1])]">
<Part>
<xsl:apply-templates select="*[not(starts-with(name(), 'Attr'))]"/>
<xsl:apply-templates mode="attr" select="key('kPartById', PartID)"/>
</Part>
</xsl:template>
<xsl:template match="Part" mode="attr">
<attrs>
<xsl:apply-templates select="*[starts-with(name(), 'Attr')]"/>
</attrs>
</xsl:template>
<xsl:template match="Part"/>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<Parts>
<Part>
<MsgID>ABNHH877JJ</MsgID>
<PartID>10</PartID>
<Attr1>Part10-Attr1</Attr1>
<Attr2>Part10-Attr2</Attr2>
</Part>
<Part>
<MsgID>ABNHH877JJIUJ1</MsgID>
<PartID>10</PartID>
<Attr1>Part10-I-Attr1</Attr1>
<Attr2>Part10-I-Attr2</Attr2>
</Part>
<Part>
<MsgID>ABNHH877JJGHJ</MsgID>
<PartID>20</PartID>
<Attr1>Part20-Attr1</Attr1>
<Attr2>Part20-Attr2</Attr2>
</Part>
</Parts>
产生了想要的正确结果:
<Parts>
<Part>
<MsgID>ABNHH877JJ</MsgID>
<PartID>10</PartID>
<attrs>
<Attr1>Part10-Attr1</Attr1>
<Attr2>Part10-Attr2</Attr2>
</attrs>
<attrs>
<Attr1>Part10-I-Attr1</Attr1>
<Attr2>Part10-I-Attr2</Attr2>
</attrs>
</Part>
<Part>
<MsgID>ABNHH877JJGHJ</MsgID>
<PartID>20</PartID>
<attrs>
<Attr1>Part20-Attr1</Attr1>
<Attr2>Part20-Attr2</Attr2>
</attrs>
</Part>
</Parts>
答案 2 :(得分:1)
我一直在寻找这种转变(主要细节),我得到了一个不同的解决方案,在这里我与你分享。
这是我的想法,我需要打破2个字段Key1和Key2(可能还有一个),我需要只做一次标题和每个输入时间的细节。
<!-- start -->
<xsl:template match="/">
<xsl:for-each select="/parentNode/entry">
<!-- Current Key values -->
<xsl:variable name="Key1"><xsl:value-of select="properties/Key1"/></xsl:variable>
<xsl:variable name="Key2"><xsl:value-of select="properties/Key2"/></xsl:variable>
<!-- Previous key values -->
<xsl:variable name="PrevKey1"><xsl:value-of select="preceding-sibling::entry[1]/properties/Key1"></xsl:value-of></xsl:variable>
<xsl:variable name="PrevKey2"><xsl:value-of select="preceding-sibling::entry[1]/properties/Key2"></xsl:value-of></xsl:variable>
<!-- Compare Values, if differents then put the header -->
<xsl:if test="$PrevKey1 != $Key or $PrevKey2 != $Key">
<!-- Put here whatever you want for the header, just this time -->
</xsl:if>
<!-- Put here whatever you want for the details, every iteration -->
</xsl:for-each>
</xsl:template>
<!-- ends -->