2013-09-26 33 views
0

我有一个输入XML转换给定的XML到另一个XML像
XML输入:使用XSLT

<parent> 
     <child> 
      <child2 name="Action">Change</child2> 
      <child1 name="Change"> 

       <child2 name="Dest_Author">Author1</child2> 

       <child2 name="Book1">BookID1</child2> 
       <child2 name="Type1">General</child2> 
       <child2 name="Pages1">100</child2> 

       <child2 name="Book2">BookID2</child2> 
       <child2 name="Type2">Cooking</child2> 
       <child2 name="Pages2">200</child2> 

       <child2 name="Orig_Author">Author2</child2> 

       <child2 name="Book1">BookID3</child2> 
       <child2 name="Type1">General</child2> 
       <child2 name="Pages1">150</child2> 

       <child2 name="Book2">BookID4</child2> 
       <child2 name="Type2">Cooking</child2> 
       <child2 name="Pages2">120</child2> 

      </child1> 
     </child> 
    </parent> 

我想将其转换为下面的XML使用XSLT转换
预期的XML输出:

<list> 
     <author id="Author1"> 
      <book> 
       <id>BookID1</id> 
       <type>General</type> 
       <pages>100</pages> 
      </book> 
      <book> 
       <id>BookID1</id> 
       <type>Cooking</type> 
       <pages>200</pages> 
      </book> 
     </author>  
     <author id="Author2"> 
      <book> 
       <id>BookID1</id> 
       <type>General</type> 
       <pages>150</pages> 
      </book> 
      <book> 
       <id>BookID1</id> 
       <type>Cooking</type> 
       <pages>120</pages> 
      </book> 
     </author> 
    </list> 

我试过使用xslt转换它,但无法做到这一点。 我的XSLT看起来像下面

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" omit-xml-declaration="yes" /> 
    <xsl:strip-space elements="*" /> 
    <xsl:template match="/"> 
     <xsl:apply-templates /> 
    </xsl:template> 
    <xsl:template match="parent"> 
     <list> 
      <xsl:apply-templates /> 
     </list> 
    </xsl:template> 
    <xsl:template match="child"> 
     <xsl:apply-templates /> 
    </xsl:template> 
    <xsl:template match="child1"> 
     <xsl:choose> 
      <xsl:when test="./@name='Change'"> 
       <author> 
        <xsl:attribute name="id"><xsl:value-of 
         select="./child2[@name='Dest_Author']" /></xsl:attribute> 
        <xsl:apply-templates /> 
       </author> 
      </xsl:when> 
     </xsl:choose> 
    </xsl:template> 
    <xsl:template match="child2"> 
     <xsl:choose> 
      <xsl:when test="contains(@name,'Orig_Author')"> 
       <!-- I thought of changing the below code(line no 36-38) as 
       </author> 
       <author> 
        <xsl:attribute name="id"><xsl:value-of select="text()"/></xsl:attribute> 
       but if do this it throws error "The element type "xsl:when" must be terminated by the matching end-tag "</xsl:when>"." 
      --> 
       <author> 
        <xsl:attribute name="id"><xsl:value-of select="text()"/></xsl:attribute> 
       </author> 
      </xsl:when> 

      <xsl:when test="contains(@name,'Book')"> 
       <book> 
        <id> 
         <xsl:value-of select="text()" /> 
        </id> 
        <xsl:variable name="next" 
         select="./following-sibling::node()[@name!=''][1]"></xsl:variable> 
        <xsl:choose> 
         <xsl:when test="contains($next/@name,'Type')"> 
          <type> 
           <xsl:value-of select="$next" /> 
          </type> 
          <pages> 
           <xsl:value-of select="$next/following-sibling::node()[@name!=''][1]" /> 
          </pages> 
         </xsl:when> 
         <xsl:when test="contains($next/@name,'Pages')"> 
          <pages> 
           <xsl:value-of select="$next" /> 
          </pages> 
         </xsl:when> 
        </xsl:choose> 
       </book> 
      </xsl:when> 
      <xsl:otherwise>  
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

XSLT输出:

<list> 
    <author id="Author1"> 
     <book> 
      <id>BookID1</id> 
      <type>General</type> 
      <pages>100</pages> 
     </book> 
     <book> 
      <id>BookID2</id> 
      <type>Cooking</type> 
      <pages>200</pages> 
     </book> 
     <author id="Author2"/> 
     <book> 
      <id>BookID3</id> 
      <type>General</type> 
      <pages>150</pages> 
     </book> 
     <book> 
      <id>BookID4</id> 
      <type>Cooking</type> 
      <pages>120</pages> 
     </book> 
    </author> 
</list> 

有人可以帮助我,告诉什么改变XSLT代码需要来获得正确的输出

+0

你的XSLT是什么样的?而不是给你的代码,它可能是你的代码不远处。 –

+0

欢迎来到堆栈溢出!看起来你希望我们为你写一些代码。尽管许多用户愿意为遇险的编码人员编写代码,但他们通常只在海报已尝试自行解决问题时才提供帮助。证明这一努力的一个好方法是包含迄今为止编写的代码,示例输入(如果有的话),期望的输出和实际获得的输出(控制台输出,堆栈跟踪,编译器错误 - 无论是适用)。您提供的详细信息越多,您可能收到的答案越多 – dhein

+0

我已经添加了我的xslt – SAM

回答

0

我会将此视为一个分组问题。要附加的每个child2他的名字并没有包括_Author其最近的前一个兄弟名叫确实包括_Author,并产生每组一个author元素。然后在要将每个非Book元素附加到其最近的前一个Book的组内并为每个组生成一个book元素。

XSLT的概念是它可以用来对元素进行分组。我将定义两个密钥,第一

<xsl:key name="booksByAuthor" match="child2[starts-with(@name, 'Book')]" 
    use="generate-id(preceding-sibling::child2[contains(@name, '_Author')][1])" /> 

这需要每个Book(即child2[@name = 'Book1' or @name='Book2' or ....])并给它分配基于最近的前面的作者的身份(generate-id)的分组密钥。第二个关键

<xsl:key name="bookDetails" 
    match="child2[not(contains(@name, '_Author') or starts-with(@name, 'Book'))]" 
    use="generate-id(preceding-sibling::child2[starts-with(@name, 'Book')][1])" /> 

组所有的“细节”的元素(那些不要么Something_AuthorBookN)可以通过最近的前簿。这些键为您提供了层次结构,并让您将其余的样式表编码为模板匹配的常规系统。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" omit-xml-declaration="yes" /> 
    <xsl:strip-space elements="*" /> 

    <xsl:key name="booksByAuthor" match="child2[starts-with(@name, 'Book')]" 
     use="generate-id(preceding-sibling::child2[contains(@name, '_Author')][1])" /> 

    <xsl:key name="bookDetails" 
     match="child2[not(contains(@name, '_Author') or starts-with(@name, 'Book'))]" 
     use="generate-id(preceding-sibling::child2[starts-with(@name, 'Book')][1])" /> 

    <xsl:template match="/parent"> 
     <list> 
      <!-- process all the authors --> 
      <xsl:apply-templates select=".//child2[contains(@name, '_Author')]" /> 
     </list> 
    </xsl:template> 

    <xsl:template match="child2[contains(@name, '_Author')]"> 
     <!-- for each author, create an author element --> 
     <author id="{.}"> 
      <!-- and process this author's books --> 
      <xsl:apply-templates select="key('booksByAuthor', generate-id())" /> 
     </author> 
    </xsl:template> 

    <xsl:template match="child2[starts-with(@name, 'Book')]"> 
     <!-- for each book, create a book element --> 
     <book> 
      <id><xsl:value-of select="." /></id> 
      <!-- and process this book's details --> 
      <xsl:apply-templates select="key('bookDetails', generate-id())" /> 
     </book> 
    </xsl:template> 

    <xsl:template match="child2[starts-with(@name, 'Type')]"> 
     <type><xsl:value-of select="." /></type> 
    </xsl:template> 

    <xsl:template match="child2[starts-with(@name, 'Pages')]"> 
     <pages><xsl:value-of select="." /></pages> 
    </xsl:template> 
</xsl:stylesheet> 

如果您还有其他孩子的类型,如Publisher1Publisher2,...那么你只需沿着相同的路线为TypePages那些添加额外的模板。