使用XSLT将输入XML转换为其他XML

时间:2012-07-02 00:42:18

标签: xml xslt xml-parsing

我是初学者,想学习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>

1 个答案:

答案 0 :(得分:1)

此转化

<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>