2012-03-20 92 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