我有一个输入xml,如
XML输入:
<parent>
<child>
<child2 name="Action">Change</child2>
<child1 name="Change">
<child2 name="Dest_Author">Author1</child2>
<child2 name="Book1">BookID1</child2>
<child2 name="Type1">General</child2>
<child2 name="Pages1">100</child2>
<child2 name="Book2">BookID2</child2>
<child2 name="Type2">Cooking</child2>
<child2 name="Pages2">200</child2>
<child2 name="Orig_Author">Author2</child2>
<child2 name="Book1">BookID3</child2>
<child2 name="Type1">General</child2>
<child2 name="Pages1">150</child2>
<child2 name="Book2">BookID4</child2>
<child2 name="Type2">Cooking</child2>
<child2 name="Pages2">120</child2>
</child1>
</child>
</parent>
我想使用xslt转换将其转换为以下xml 预期的XML输出:
<list>
<author id="Author1">
<book>
<id>BookID1</id>
<type>General</type>
<pages>100</pages>
</book>
<book>
<id>BookID1</id>
<type>Cooking</type>
<pages>200</pages>
</book>
</author>
<author id="Author2">
<book>
<id>BookID1</id>
<type>General</type>
<pages>150</pages>
</book>
<book>
<id>BookID1</id>
<type>Cooking</type>
<pages>120</pages>
</book>
</author>
</list>
我尝试使用xslt转换它,但无法这样做。 我的xslt如下所示
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="parent">
<list>
<xsl:apply-templates />
</list>
</xsl:template>
<xsl:template match="child">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="child1">
<xsl:choose>
<xsl:when test="./@name='Change'">
<author>
<xsl:attribute name="id"><xsl:value-of
select="./child2[@name='Dest_Author']" /></xsl:attribute>
<xsl:apply-templates />
</author>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="child2">
<xsl:choose>
<xsl:when test="contains(@name,'Orig_Author')">
<!-- I thought of changing the below code(line no 36-38) as
</author>
<author>
<xsl:attribute name="id"><xsl:value-of select="text()"/></xsl:attribute>
but if do this it throws error "The element type "xsl:when" must be terminated by the matching end-tag "</xsl:when>"."
-->
<author>
<xsl:attribute name="id"><xsl:value-of select="text()"/></xsl:attribute>
</author>
</xsl:when>
<xsl:when test="contains(@name,'Book')">
<book>
<id>
<xsl:value-of select="text()" />
</id>
<xsl:variable name="next"
select="./following-sibling::node()[@name!=''][1]"></xsl:variable>
<xsl:choose>
<xsl:when test="contains($next/@name,'Type')">
<type>
<xsl:value-of select="$next" />
</type>
<pages>
<xsl:value-of select="$next/following-sibling::node()[@name!=''][1]" />
</pages>
</xsl:when>
<xsl:when test="contains($next/@name,'Pages')">
<pages>
<xsl:value-of select="$next" />
</pages>
</xsl:when>
</xsl:choose>
</book>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
XSLT输出:
<list>
<author id="Author1">
<book>
<id>BookID1</id>
<type>General</type>
<pages>100</pages>
</book>
<book>
<id>BookID2</id>
<type>Cooking</type>
<pages>200</pages>
</book>
<author id="Author2"/>
<book>
<id>BookID3</id>
<type>General</type>
<pages>150</pages>
</book>
<book>
<id>BookID4</id>
<type>Cooking</type>
<pages>120</pages>
</book>
</author>
</list>
有人可以帮助我并告诉xslt代码需要哪些更改才能获得正确的输出
答案 0 :(得分:0)
我会将此视为分组问题。您希望将名称 not 包含child2
的每个_Author
附加到其最近的前一个兄弟,其名称 包括_Author
,并且每组生成一个author
元素。然后,您希望将每个非Book
元素附加到其最近的前一个Book
,并为每个组生成一个book
元素。
XSLT具有 keys 的概念,可用于对元素进行分组。我会定义两个键,第一个
<xsl:key name="booksByAuthor" match="child2[starts-with(@name, 'Book')]"
use="generate-id(preceding-sibling::child2[contains(@name, '_Author')][1])" />
取每个Book
(即child2[@name = 'Book1' or @name='Book2' or ....]
),并根据最近的前作者的身份(generate-id
)为其分配一个分组键。第二个关键
<xsl:key name="bookDetails"
match="child2[not(contains(@name, '_Author') or starts-with(@name, 'Book'))]"
use="generate-id(preceding-sibling::child2[starts-with(@name, 'Book')][1])" />
将所有“详细信息”元素(不是Something_Author
或BookN
)的元素按其最近的前一个图书分组。这些键为您提供了层次结构,并允许您将样式表的其余部分编码为模板匹配的常规系统。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:key name="booksByAuthor" match="child2[starts-with(@name, 'Book')]"
use="generate-id(preceding-sibling::child2[contains(@name, '_Author')][1])" />
<xsl:key name="bookDetails"
match="child2[not(contains(@name, '_Author') or starts-with(@name, 'Book'))]"
use="generate-id(preceding-sibling::child2[starts-with(@name, 'Book')][1])" />
<xsl:template match="/parent">
<list>
<!-- process all the authors -->
<xsl:apply-templates select=".//child2[contains(@name, '_Author')]" />
</list>
</xsl:template>
<xsl:template match="child2[contains(@name, '_Author')]">
<!-- for each author, create an author element -->
<author id="{.}">
<!-- and process this author's books -->
<xsl:apply-templates select="key('booksByAuthor', generate-id())" />
</author>
</xsl:template>
<xsl:template match="child2[starts-with(@name, 'Book')]">
<!-- for each book, create a book element -->
<book>
<id><xsl:value-of select="." /></id>
<!-- and process this book's details -->
<xsl:apply-templates select="key('bookDetails', generate-id())" />
</book>
</xsl:template>
<xsl:template match="child2[starts-with(@name, 'Type')]">
<type><xsl:value-of select="." /></type>
</xsl:template>
<xsl:template match="child2[starts-with(@name, 'Pages')]">
<pages><xsl:value-of select="." /></pages>
</xsl:template>
</xsl:stylesheet>
如果您有其他子类型,例如Publisher1
,Publisher2
,...那么您只需添加与Type
和Pages
相同的其他模板的。