使用xslt将给定的xml转换为另一个xml
我有一个类似于使用xslt将给定的xml转换为另一个xml,xml,xslt,Xml,Xslt,我有一个类似于 XML输入: <parent> <child> <child2 name="Action">Change</child2> <child1 name="Change"> <child2 name="Dest_Author">Author1</child2> &
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>
改变
作者1
书号1
一般的
100
图书编号2
烹饪
200
作者2
书号3
一般的
150
书号4
烹饪
120
我想使用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>
书号1
一般的
100
书号1
烹饪
200
书号1
一般的
150
书号1
烹饪
120
我尝试使用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>
书号1
一般的
100
图书编号2
烹饪
200
书号3
一般的
150
书号4
烹饪
120
有人能帮我告诉我xslt代码需要做哪些更改才能获得正确的输出吗?我将把这视为一个分组问题。您希望将每个名不包含
\u Author
的child2
附加到其最近的前一个兄弟姐妹(其名包含\u Author
),并为每个组生成一个Author
元素。然后在组中,您希望将每个非Book
元素附加到其最近的前一个Book
元素,并为每个组生成一个Book
元素
XSLT有键的概念,可以用来对元素进行分组。首先,我要定义两个键
<xsl:key name="booksByAuthor" match="child2[starts-with(@name, 'Book')]"
use="generate-id(preceding-sibling::child2[contains(@name, '_Author')][1])" />
将所有“细节”元素(那些不是Something\u 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
。。。然后,您只需沿着与类型
和页面
相同的行添加其他模板。您的XSLT是什么样子的?与其给你代码,还不如说你的代码并不遥远。欢迎来到堆栈溢出!看起来你想让我们为你写些代码。虽然许多用户愿意为陷入困境的程序员编写代码,但他们通常只在海报已经试图自己解决问题时才提供帮助。演示这项工作的一个好方法是,包括您迄今为止编写的代码、示例输入(如果有)、预期输出和实际获得的输出(控制台输出、堆栈跟踪、编译器错误——任何适用的)。您提供的详细信息越多,您可能收到的答案就越多您是否真的希望所需输出中的所有书籍都具有相同的idBookID1
,或者这是一个打字错误?输出正是我想要的。无论如何,下面的代码工作正常。谢谢
<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>