我有一个XML文件 authors.xml ,如下所示:
<?xml version="1.0" encoding="ISO-8859-1"?>
<authors>
<author>
<name>Leonardo da Vinci</name>
<nationality>Italian</nationality>
</author>
<author>
<name>Pablo Picasso</name>
<nationality>Spanish</nationality>
</author>
</authors>
和另一个列出其作品 artwork.xml 的文件如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<artworks>
<artwork>
<title>Mona Lisa</title>
<author>Leonardo da Vinci</author>
<date>1497</date>
<form>painting</form>
</artwork>
<artwork>
<title>Vitruvian Man</title>
<author>Leonardo da Vinci</author>
<date>1499</date>
<form>painting</form>
</artwork>
<artwork>
<title>Absinthe Drinker</title>
<author>Pablo Picasso</author>
<date>1479</date>
<form>painting</form>
</artwork>
<artwork>
<title>Chicago Picasso</title>
<author>Pablo Picasso</author>
<date>1950</date>
<form>sculpture</form>
</artwork>
</artworks>
我希望将这两个XML文件合并到另一个处理过的XML文件中。 XSLT将列出所有作者,并在其中列出与该特定作者相关的所有艺术作品,并按艺术作品形式对其进行分组。 XSLT还将计算图稿组的数量。组的持续时间也作为元素属性添加。这在下面的XML文件中进一步说明:
<?xml version="1.0" encoding="UTF-8" ?>
<authors>
<author>
<name>Leonardo da Vinci</name>
<nationality>Italian</nationality>
<artworks form="painting" duration="1497-1499" quantity="2">
<artwork date="1497">
<title>Mona Lisa</title>
</artwork>
<artwork date="1499">
<title>Vitruvian Man</title>
</artwork>
</artworks>
</author>
<author>
<name>Pablo Picasso</name>
<nationality>Spanish</nationality>
<artworks form="painting" duration="1479-1479" quantity="1">
<artwork date="1479">
<title>Absinthe Drinker</title>
</artwork>
</artworks>
<artworks form="sculpture" duration="1950-1950" quantity="1">
<artwork date="1950">
<title>Chicago Picasso</title>
</artwork>
</artworks>
</author>
</authors>
我还是新手。我设法做的是获取所有作者的部分,现在我不确定如何从其他XML文件中提取数据,同时还要计算艺术品的出现等等。我在程序编程方面非常有经验,比如C或C ++,但这种声明式编程方法真的让我头脑发热!希望有人可以指出我正确的方向,以便我能做到这一点。
答案 0 :(得分:5)
此样式表将生成您期望的输出,使用authors.xml
文件作为输入源,并将artworks.xml
放在同一目录中:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:variable name="artworks" select="doc('artworks.xml')/artworks"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="authors/author">
<xsl:copy>
<xsl:copy-of select="name"/>
<xsl:copy-of select="nationality"/>
<xsl:for-each-group
select="$artworks/artwork[author=current()/name]"
group-by="form">
<artworks form="{form}"
duration="{min(current-group()/date)}-{max(current-group()/date)}"
quantity="{count(current-group())}">
<xsl:apply-templates select="current-group()"/>
</artworks>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="artwork">
<artwork date="{date}">
<title><xsl:value-of select="title"/></title>
</artwork>
</xsl:template>
</xsl:stylesheet>
以下是对上述代码的解释:
我使用xsl:variable
来引用导入文档中的artworks
子树:
<xsl:variable name="artworks" select="doc('artworks.xml')/artworks"/>
此模板是一个标识转换,它将匹配任何节点和属性并将其复制到输出。它的优先级低于其他两个模板,因此只有在其他模板不匹配时才会调用它:
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
第二个模板必须与authors/author
匹配(而不是author
,因为在处理两个文档时都会调用它,而author
内还有另一个artwork
。 copy-of
元素复制所选节点的整个子树(元素,内容和属性)。
<xsl:template match="authors/author">
<xsl:copy>
<xsl:copy-of select="name"/>
<xsl:copy-of select="nationality"/>
...
</xsl:copy>
</xsl:template>
for-each-group
对来自artwork
文件的每个artworks.xml
元素进行迭代,该文件与输入中当前节点的name
元素具有相同的author
文件(authors.xml
)。它按form
分组。您使用current-group()
来引用当前组,您需要计算max
和min
日期,计算数量并打印<artwork>
个节点。
<xsl:for-each-group
select="$artworks/artwork[author=current()/name]"
group-by="form">
<artworks form="{form}"
duration="{min(current-group()/date)}-{max(current-group()/date)}"
quantity="{count(current-group())}">
<xsl:apply-templates select="current-group()"/>
</artworks>
</xsl:for-each-group>
最后,此模板格式化每个artwork
节点:
<xsl:template match="artwork">
<artwork date="{date}">
<title><xsl:value-of select="title"/></title>
</artwork>
</xsl:template>
你可以以不同的方式完成所有这些操作,在单个根/
匹配模板和几个嵌套的for-each
块中,但在编码时使用模板是一个更好的做法XSLT。