2012-03-20 50 views
1

我将相同的多标记元素转换为不同的记录。 在这我使用XSLT。 我需要XSLT帮助。 我得到第一个标签结果是正确的,螺母idont知道为什么第二个标签没有得到。使用XSLT将多级XML转换为平面XML

说明:: * 在第一张CD:单个atrist到许多标题。我想根据标题将其分成不同的标签。 第二张CD:第一个艺术家的第一个标题和第二个艺术家的第二个标题。我也需要根据标题和艺术家的不同(两个)CD标签来制作[第一个标题 - 第一个艺术家和第二个标题 - 第二个aritst]。 *

我的源XML就像是继::

<?xml version="1.0" encoding="ISO-8859-1"?> 
<!-- Edited by XMLSpy® --> 
<catalog> 
    <cd> 
     <title>Burlesque</title>   
     <title>Empire</title> 
     <title>Emp</title> 
     <title>Em</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Hide your</title> 
     <title>heart</title> 
     <artist>Bonnie</artist> 
     <artist> Tyler</artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
    <cd> 
     <title/> 
     <artist>Dolly Parton</artist> 
     <country>USA</country> 
     <company>RCA</company> 
     <price>9.90</price> 
     <year>1982</year> 
    </cd> 
</catalog> 

XSLT ::

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:key name="k" match="title" use="text()"/> 
    <xsl:key name="l" match="artist" use="text()"/> 
      <xsl:template match="/"> 
     <catalog> 
      <xsl:apply-templates select="//cd/title | artist[not(node() = preceding-sibling::node())]"/> 
     </catalog> 
    </xsl:template> 
    <xsl:template match="//cd"> 
     <xsl:param name="title" select="title"/> 
     <xsl:param name="artist" select="artist"/> 
     <cd> 
      <xsl:copy-of select="key('k', $title)[not(node() = preceding-sibling::node())]"/> 
      <xsl:copy-of select="key('l', $artist)[not(node() = preceding-sibling::node())]"/> 
      <xsl:copy-of select="./*[name() != 'title' and 'artist']"/> 
     </cd> 
    </xsl:template> 
    <xsl:template match="title"> 
      <xsl:apply-templates select=".."> 
      <xsl:with-param name="title" select="."/> 
     </xsl:apply-templates> 
    </xsl:template> 
</xsl:stylesheet> 

什么我得到::

<?xml version="1.0" encoding="utf-8"?> 
<catalog> 
    <cd> 
    <title>Burlesque</title> 
    <artist>Bob Dylan</artist> 
    <artist>Bob Dylan</artist> 
    <country>USA</country> 
    <company>Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Empire</title> 
    <artist>Bob Dylan</artist> 
    <artist>Bob Dylan</artist> 
    <country>USA</country> 
    <company>Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Emp</title> 
    <artist>Bob Dylan</artist> 
    <artist>Bob Dylan</artist> 
    <country>USA</country> 
    <company>Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Em</title> 
    <artist>Bob Dylan</artist> 
    <artist>Bob Dylan</artist> 
    <country>USA</country> 
    <company>Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Hide your</title> 
    <artist>Bonnie</artist> 
    <artist> Tyler</artist> 
    <artist>Bonnie</artist> 
    <artist> Tyler</artist> 
    <country>UK</country> 
    <company>CBS Records</company> 
    <price>9.90</price> 
    <year>1988</year> 
    </cd> 
    <cd> 
    <title>heart</title> 
    <artist>Bonnie</artist> 
    <artist> Tyler</artist> 
    <artist>Bonnie</artist> 
    <artist> Tyler</artist> 
    <country>UK</country> 
    <company>CBS Records</company> 
    <price>9.90</price> 
    <year>1988</year> 
    </cd> 
    <cd> 
    <artist>Dolly Parton</artist> 
    <artist>Dolly Parton</artist> 
    <country>USA</country> 
    <company>RCA</company> 
    <price>9.90</price> 
    <year>1982</year> 
    </cd> 
</catalog> 

我需要什么::

<?xml version="1.0" encoding="utf-8"?> 
<catalog> 
    <cd> 
    <title>Burlesque</title> 
    <artist>Bob Dylan</artist> 
    <country>USA</country> 
    <company>Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Empire</title> 
    <artist>Bob Dylan</artist> 
    <country>USA</country> 
    <company>Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Emp</title> 
    <artist>Bob Dylan</artist> 
    <country>USA</country> 
    <company>Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Em</title> 
    <artist>Bob Dylan</artist> 
    <country>USA</country> 
    <company>Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Hide your</title> 
    <artist>Bonnie</artist> 
    <country>UK</country> 
    <company>CBS Records</company> 
    <price>9.90</price> 
    <year>1988</year> 
    </cd> 
    <cd> 
    <title>heart</title> 
    <artist> Tyler</artist> 
    <country>UK</country> 
    <company>CBS Records</company> 
    <price>9.90</price> 
    <year>1988</year> 
    </cd> 
    <cd> 
    <artist>Dolly Parton</artist> 
    <artist>Dolly Parton</artist> 
    <country>USA</country> 
    <company>RCA</company> 
    <price>9.90</price> 
    <year>1982</year> 
    </cd> 
</catalog> 

任何人都可以帮助我吗?

回答

1

这是一个"generic XML shredding" transformation,其中该参数被设置为想要的叶节点和次要后处理的应用程序做是为了除去从结果和再缠绕两个顶部包装节点:

<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:strip-space elements="*"/> 

    <xsl:param name="pLeafNodes" select="/*/*/title"/> 

    <xsl:template match="/"> 
     <xsl:variable name="vrtfResult"> 
     <xsl:call-template name="StructRepro"/> 
     </xsl:variable> 

     <catalog> 
     <xsl:copy-of select="ext:node-set($vrtfResult)/catalog/node()"/> 
     </catalog> 
    </xsl:template> 

    <xsl:template name="StructRepro"> 
     <xsl:param name="pLeaves" select="$pLeafNodes"/> 

     <xsl:for-each select="$pLeaves"> 
     <xsl:apply-templates mode="build" select="/*"> 
      <xsl:with-param name="pChild" select="."/> 
      <xsl:with-param name="pLeaves" select="$pLeaves"/> 
     </xsl:apply-templates> 
     </xsl:for-each> 
    </xsl:template> 

     <xsl:template mode="build" match="node()|@*"> 
      <xsl:param name="pChild"/> 
      <xsl:param name="pLeaves"/> 

     <xsl:copy> 
      <xsl:apply-templates mode="build" select="@*"/> 

      <xsl:variable name="vLeafChild" select= 
      "*[count(.|$pChild) = count($pChild)]"/> 

      <xsl:choose> 
      <xsl:when test="$vLeafChild"> 
      <xsl:apply-templates mode="build" 
       select="$vLeafChild 
         | 
          node()[not(count(.|$pLeaves) = count($pLeaves))]"> 
       <xsl:with-param name="pChild" select="$pChild"/> 
       <xsl:with-param name="pLeaves" select="$pLeaves"/> 
      </xsl:apply-templates> 
      </xsl:when> 
      <xsl:otherwise> 
      <xsl:apply-templates mode="build" select= 
      "node()[not(.//*[count(.|$pLeaves) = count($pLeaves)]) 
        or 
        .//*[count(.|$pChild) = count($pChild)] 
        ] 
      "> 

       <xsl:with-param name="pChild" select="$pChild"/> 
       <xsl:with-param name="pLeaves" select="$pLeaves"/> 
      </xsl:apply-templates> 
      </xsl:otherwise> 
      </xsl:choose> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 

当这种转变是在所提供的XML文档应用:

<catalog> 
    <cd> 
     <title>Burlesque</title> 
     <title>Empire</title> 
     <title>Emp</title> 
     <title>Em</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Hide your</title> 
     <title>heart</title> 
     <artist>Bonnie</artist> 
     <artist> Tyler</artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
    <cd> 
     <title/> 
     <artist>Dolly Parton</artist> 
     <country>USA</country> 
     <company>RCA</company> 
     <price>9.90</price> 
     <year>1982</year> 
    </cd> 
</catalog> 

想要的,正确的重SULT产生

<catalog> 
    <cd> 
     <title>Burlesque</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Empire</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Emp</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Em</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Hide your</title> 
     <artist>Bonnie</artist> 
     <artist> Tyler</artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
    <cd> 
     <title>heart</title> 
     <artist>Bonnie</artist> 
     <artist> Tyler</artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
    <cd> 
     <title/> 
     <artist>Dolly Parton</artist> 
     <country>USA</country> 
     <company>RCA</company> 
     <price>9.90</price> 
     <year>1982</year> 
    </cd> 
</catalog> 

更新:该任择议定书已经改变了他的问题,他要求,对于CD的一个以上的艺术家应该有艺术家的附加分。

下面是解决方案 - 这是一个双通处理。在第一次通过时,文件被转换为catalog,其中每个cd具有单个artist。然后在第二遍是我已经在上面给出了解决方案:

<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:strip-space elements="*"/> 

     <xsl:template match="/"> 

      <xsl:variable name="vrtfPass1"> 
      <xsl:apply-templates mode="pass1"/> 
      </xsl:variable> 

      <xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)"/> 

      <xsl:variable name="pLeafNodes" select="$vPass1/*/*/title"/> 

      <xsl:variable name="vrtfResult"> 
      <xsl:call-template name="StructRepro"> 
       <xsl:with-param name="pLeaves" select="$pLeafNodes"/> 
      </xsl:call-template> 
      </xsl:variable> 

      <catalog> 
      <xsl:copy-of select="ext:node-set($vrtfResult)/catalog/node()"/> 
      </catalog> 
     </xsl:template> 

     <xsl:template name="StructRepro"> 
      <xsl:param name="pLeaves"/> 

      <xsl:variable name="vDoc" select= 
       "$pLeaves[1]/ancestor::node()[last()]"/> 

      <xsl:for-each select="$pLeaves"> 
      <xsl:apply-templates mode="build" select="$vDoc/*"> 
       <xsl:with-param name="pChild" select="."/> 
       <xsl:with-param name="pLeaves" select="$pLeaves"/> 
      </xsl:apply-templates> 
      </xsl:for-each> 
     </xsl:template> 

      <xsl:template mode="build" match="node()|@*"> 
       <xsl:param name="pChild"/> 
       <xsl:param name="pLeaves"/> 

      <xsl:copy> 
       <xsl:apply-templates mode="build" select="@*"/> 

       <xsl:variable name="vLeafChild" select= 
       "*[count(.|$pChild) = count($pChild)]"/> 

       <xsl:choose> 
       <xsl:when test="$vLeafChild"> 
       <xsl:apply-templates mode="build" 
        select="$vLeafChild 
          | 
           node()[not(count(.|$pLeaves) = count($pLeaves))]"> 
        <xsl:with-param name="pChild" select="$pChild"/> 
        <xsl:with-param name="pLeaves" select="$pLeaves"/> 
       </xsl:apply-templates> 
       </xsl:when> 
       <xsl:otherwise> 
       <xsl:apply-templates mode="build" select= 
       "node()[not(.//*[count(.|$pLeaves) = count($pLeaves)]) 
         or 
         .//*[count(.|$pChild) = count($pChild)] 
         ] 
       "> 

        <xsl:with-param name="pChild" select="$pChild"/> 
        <xsl:with-param name="pLeaves" select="$pLeaves"/> 
       </xsl:apply-templates> 
       </xsl:otherwise> 
       </xsl:choose> 
      </xsl:copy> 
     </xsl:template> 

<xsl:template match="node()|@*" mode="pass1"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*" mode="pass1"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="cd[artist[2]]" mode="pass1"> 
    <xsl:for-each select="artist"> 
    <xsl:apply-templates select=".." mode="singleArtist"> 
    <xsl:with-param name="pArtistPos" select="position()"/> 
    </xsl:apply-templates> 
    </xsl:for-each> 
</xsl:template> 

<xsl:template match="cd" mode="singleArtist"> 
    <xsl:param name="pArtistPos"/> 

    <cd> 
    <xsl:apply-templates mode="pass1" select= 
     "title[position() = $pArtistPos]"/> 
    <xsl:apply-templates mode="pass1" select= 
     "artist[position() = $pArtistPos]"/> 
    <xsl:apply-templates mode="pass1" select= 
     "node()[not(self::title or self::artist)]"/> 
    </cd> 
</xsl:template> 

<xsl:template match="text()"/> 
</xsl:stylesheet> 

当这种转化是在同一个XML文档(上文),其结果现在满足附加要求施加:

<catalog> 
    <cd> 
     <title>Burlesque</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Empire</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Emp</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Em</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Hide your</title> 
     <artist>Bonnie</artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
    <cd> 
     <title>heart</title> 
     <artist> Tyler</artist> 
     <country>UK</country> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
    <cd> 
     <title/> 
     <artist>Dolly Parton</artist> 
     <country>USA</country> 
     <company>RCA</company> 
     <price>9.90</price> 
     <year>1982</year> 
    </cd> 
</catalog> 
+0

一旦请参阅标签。它来了两次。隐藏你的邦妮泰勒英国 CBS唱片 9.90 1988年心脏邦妮泰勒英国 CBS唱片 9.90 1988年 2012-03-20 13:12:59

+0

@ ram.bi:我明白了,所以你想要的比简单的粉碎更加复杂,不同的艺术家需要结合不同的标题。但是,你必须编辑这个问题,并且展开哪个艺术家应该与哪个标题匹配。两位艺术家可能会唱同一首歌曲(我认为),或者两位艺术家都唱这两首歌曲,或者第一位歌手唱第二首歌曲(想象艺术家和歌曲是按字母顺序排列的,请编辑问题并指定确切的规则 – 2012-03-20 13:37:18

+0

嗨Dimitre,谢谢你的回应,我添加了解释,可以请把我放在正确的方向。 – 2012-03-21 09:46:47