我是一个初学者,想了解XSLT。 我偶然发现了一个问题,使用XSLT将输入XML文件转换为另一个XML文件。
我输入XML文件:
<album>
<album_num>hi.hello</album_num>
<album_name>Cocktail</album_name>
</album>
<album>
<album_num>hey.hello</album_num>
<album_name>Mocktail</album_name>
</album>
<album>
<album_num>hey.mello</album_num>
<album_name>Monkeytail</album_name>
</album>
<album>
<album_num>hey.yellow</album_num>
<album_name>Donkeytail</album_name>
</album>
<album>
<album_num>swallow</album_num>
<album_name>abc</album_name>
</album>
我想获得一个像这样的输出XML文件:
<album>
<album_num>
<hi>
<hello>cocktail</hello>
</hi>
</album_num>
<album_num>
<hey>
<hello>MockTail</hello>
<mello>Monkeytail</mello>
<yellow>Donkeytail</yellow>
</hey>
</album_num>
<album_num>
<swallow>abc</swallow>
</album_num>
</album>
我通过创建变量尝试的第一个部分,但有一个问题一个元素合并相似的元素。 任何代码可以帮助我学习。
我的代码:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<album>
<xsl:variable name="fstval" select='substring-before(//album/album_num,".")'/>
<xsl:variable name="secval" select='substring-after(//album/album_num,".")'/>
<xsl:variable name="valtoappend" select='//album/album_name'/>
<album_num>
<xsl:element name="{$fstval}">
<xsl:element name="{$secval}">
<xsl:value-of select="$valtoappend"/>
</xsl:element>
</xsl:element>
</xsl:for-each>
</album_num>
</album>
</xsl:template>
</xsl:stylesheet>
这一转变 :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kAlbumByChildName" match="album" use="name(album_num/*[1])"/>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates mode="pass2" select=
"ext:node-set($vrtfPass1)/*
[generate-id()
=
generate-id(key('kAlbumByChildName', name(album_num/*[1]))[1])
]
"/>
</xsl:template>
<xsl:template match="album">
<album>
<album_num>
<xsl:element name="{substring-before(album_num, '.')}">
<xsl:element name="{substring-after(album_num, '.')}">
<xsl:value-of select="album_name"/>
</xsl:element>
</xsl:element>
</album_num>
</album>
</xsl:template>
<xsl:template match="album" mode="pass2">
<album>
<album_num>
<xsl:apply-templates select="*/*[1]" mode="pass2"/>
</album_num>
</album>
</xsl:template>
<xsl:template match="album_num/*" mode="pass2">
<xsl:copy>
<xsl:copy-of select="key('kAlbumByChildName', name())/*/*/*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当施加在以下文件 (提供的XML片段包装在单个顶部元件,使之成为良好的XML文档):
<t>
<album>
<album_num>hi.hello</album_num>
<album_name>Cocktail</album_name>
</album>
<album>
<album_num>hey.hello</album_num>
<album_name>Mocktail</album_name>
</album>
<album>
<album_num>hey.mello</album_num>
<album_name>Monkeytail</album_name>
</album>
<album>
<album_num>hey.yellow</album_num>
<album_name>Donkeytail</album_name>
</album>
</t>
产生想要的,正确的结果:
<album>
<album_num>
<hi>
<hello>Cocktail</hello>
</hi>
</album_num>
</album>
<album>
<album_num>
<hey>
<hello>Mocktail</hello>
<mello>Monkeytail</mello>
<yellow>Donkeytail</yellow>
</hey>
</album_num>
</album>
说明 :
这是一个双通道改造。 第一遍的结果是 :
<album>
<album_num>
<hi>
<hello>Cocktail</hello>
</hi>
</album_num>
</album>
<album>
<album_num>
<hey>
<hello>Mocktail</hello>
</hey>
</album_num>
</album>
<album>
<album_num>
<hey>
<mello>Monkeytail</mello>
</hey>
</album_num>
</album>
<album>
<album_num>
<hey>
<yellow>Donkeytail</yellow>
</hey>
</album_num>
</album>
第二遍是标准Muenchian分组的。
更新 :
提出这个问题,并接收正确答案两天后,在OP改变了源XML文档,想要的结果。
这个稍微修改转变 :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kAlbumByChildName" match="album" use="name(album_num/*[1])"/>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates mode="pass2" select=
"ext:node-set($vrtfPass1)/*
[generate-id()
=
generate-id(key('kAlbumByChildName', name(album_num/*[1]))[1])
or
not(album_num/*)
]
"/>
</xsl:template>
<xsl:template match="album[contains(album_num, '.')]">
<album>
<album_num>
<xsl:element name="{substring-before(album_num, '.')}">
<xsl:element name="{substring-after(album_num, '.')}">
<xsl:value-of select="album_name"/>
</xsl:element>
</xsl:element>
</album_num>
</album>
</xsl:template>
<xsl:template match="album">
<album>
<album_num>
<xsl:element name="{album_num}">
<xsl:value-of select="album_name"/>
</xsl:element>
</album_num>
</album>
</xsl:template>
<xsl:template match="album" mode="pass2">
<album>
<album_num>
<xsl:apply-templates select="*/*[1]" mode="pass2"/>
</album_num>
</album>
</xsl:template>
<xsl:template match="album_num/*" mode="pass2">
<xsl:copy>
<xsl:copy-of select="self::*[not(*)]/text()|key('kAlbumByChildName', name())/*/*/*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当应用于XML文档的新版本 :
<t>
<album>
<album_num>hi.hello</album_num>
<album_name>Cocktail</album_name>
</album>
<album>
<album_num>hey.hello</album_num>
<album_name>Mocktail</album_name>
</album>
<album>
<album_num>hey.mello</album_num>
<album_name>Monkeytail</album_name>
</album>
<album>
<album_num>hey.yellow</album_num>
<album_name>Donkeytail</album_name>
</album>
<album>
<album_num>swallow</album_num>
<album_name>abc</album_name>
</album>
</t>
产生新的通缉的结果 :
<album>
<album_num>
<hi>
<hello>Cocktail</hello>
</hi>
</album_num>
</album>
<album>
<album_num>
<hey>
<hello>Mocktail</hello>
<mello>Monkeytail</mello>
<yellow>Donkeytail</yellow>
</hey>
</album_num>
</album>
<album>
<album_num>
<swallow>abc</swallow>
</album_num>
</album>