通过XSLT将XML转换为另一个XML

时间:2013-01-23 07:03:54

标签: xml xslt

我有一个XML文件如下,我想将其转换为另一个XML文件。

<body>
  <outline text="A">
    <outline text="Abelson, Harold" author="Harold Abelson" title="Struktur und Interpretation von Computerprogrammen. Eine Informatik-Einführung" publisher="Springer Verlag" isbn="3540520430" year="1991"/>
    <outline text="Abrahams, Paul W." author="Paul W. Abrahams" title="Tex for the Impatient" publisher="Addison-Wesley Pub Co" isbn="0201513757" year="2000"/>
  </outline>
  <outline text="B">
    <outline text="Bach, Fred" author="Fred Bach" title="UNIX Handbuch zur Programmentwicklung" publisher="Hanser Fachbuchverlag" isbn="3446151036"/>
    <outline text="Bach, Maurice J." author="Maurice J. Bach" title="Design of the UNIX Operating System" publisher="Prentice Hall PTR" isbn="0132017997" year="1986"/>
  </outline>
</body>

这是我要转换为

的XML格式
<list>
    <books text="A">
        <book>
            <text>Abelson, Harold</text>
            <author>Harold Abelson</author>
            <title>Struktur und Interpretation von Computerprogrammen. Eine
                Informatik-Einführung</title>
            <publisher>Springer Verlag</publisher>
            <isbn>3540520430</isbn>
            <year>1991</year>
        </book>
        <book>
            <text>Abrahams, Paul W.</text>
            <author>Paul W. Abrahams</author>
            <title>Tex for the Impatient</title>
            <publisher>Addison-Wesley Pub Co</publisher>
            <isbn>0201513757</isbn>
            <year>2000</year>
        </book>

    </books>
    <books text="B">
        <book>
            <text>Bach, Fred</text>
            <author>Fred Bach</author>
            <title>UNIX Handbuch zur Programmentwicklung</title>
            <publisher>Hanser Fachbuchverlag</publisher>
            <isbn>3446151036</isbn>
            <year />
        </book>

这是我的代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml"/>
    <xsl:template match="body">
        <list> <xsl:apply-templates select="outline"/> </list>
    </xsl:template>

    <xsl:template match="outline">
    <books text= "{@text}">
        <book><xsl:apply-templates select="outline"/> 
        <text><xsl:value-of select="@text" /></text>
        <author><xsl:value-of select="@author" /></author>
        <title><xsl:value-of select="@title" /></title>
        <publisher><xsl:value-of select="@publisher" /></publisher>
        <isbn><xsl:value-of select="@isbn" /></isbn>
        <year><xsl:value-of select="@year" /></year>
        </book>
    </books>
    </xsl:template>


</xsl:stylesheet>

这是我代码的输出。

<list>
    <books text="A">
        <book>
            <books text="Abelson, Harold">
                <book>
                    <text>Abelson, Harold</text>
                    <author>Harold Abelson</author>
                    <title>Struktur und Interpretation von Computerprogrammen. Eine
                        Informatik-Einführung</title>
                    <publisher>Springer Verlag</publisher>
                    <isbn>3540520430</isbn>
                    <year>1991</year>
                </book>
            </books>

我的输出中有两个额外的元素

<books text="Abelson, Harold">
                <book>

据我所知,这可能是由这行代码引起的。我尝试了几种不同的方式,但没有工作

<xsl:template match="outline">
        <books text= "{@text}">

附加问题: 如果原始XML文件包含标题。如何消除头部和头衔。我当前的代码在新的XML文件中生成“tmp”。

<opml version="1.0">
  <head>
    <title>tmp</title>
    <expansionState></expansionState>
  </head>
  <body>
      <outline text="A">
      <outline text="Abelson, Harold" author="H

3 个答案:

答案 0 :(得分:3)

您走在正确的轨道上,但您需要两个outline模板 - 一个用于顶级outline,另一个用于孩子outlines

请用以下三个替换您的outline模板:

  <xsl:template match="head" />

  <xsl:template match="outline">
    <books text="{@text}">
      <xsl:apply-templates select="outline" />
    </books>
  </xsl:template>

  <xsl:template match="outline/outline">
    <book>
      <text>
        <xsl:value-of select="@text" />
      </text>
      <author>
        <xsl:value-of select="@author" />
      </author>
      <title>
        <xsl:value-of select="@title" />
      </title>
      <publisher>
        <xsl:value-of select="@publisher" />
      </publisher>
      <isbn>
        <xsl:value-of select="@isbn" />
      </isbn>
      <year>
        <xsl:value-of select="@year" />
      </year>
    </book>
  </xsl:template>

如果可以安全地假设源文档的属性名称与输出文档中元素的名称相匹配,则可以用这两个更短,更简化的模板替换第二个模板:

  <xsl:template match="outline/outline">
    <book>
      <xsl:apply-templates select="@text" />
      <xsl:apply-templates select="@author" />
      <xsl:apply-templates select="@title" />
      <xsl:apply-templates select="@publisher" />
      <xsl:apply-templates select="@isbn" />
      <xsl:apply-templates select="@year" />
    </book>
  </xsl:template>

  <xsl:template match="outline/outline/@*">
    <xsl:element name="{name()}">
       <xsl:value-of select="." />
    </xsl:element>
  </xsl:template>

答案 1 :(得分:3)

这是一个稍微推动的面向解决方案,它不依赖于将源XML中的元素手动拉到结果XML中。特别要注意最后一个模板。

当这个XSLT:

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

  <xsl:template match="/*">
    <list>
      <xsl:apply-templates />
    </list>
  </xsl:template>

  <xsl:template match="outline[outline]">
    <books text="{@text}">
      <xsl:apply-templates />
    </books>
  </xsl:template>

  <xsl:template match="outline[not(*)]">
    <book>
      <xsl:apply-templates select="@*" />
    </book>
  </xsl:template>

  <xsl:template match="outline[not(*)]/@*">
    <xsl:element name="{name()}">
      <xsl:value-of select="." />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

...适用于提供的源XML:

<body>
  <outline text="A">
    <outline text="Abelson, Harold" author="Harold Abelson" title="Struktur und Interpretation von Computerprogrammen. Eine Informatik-Einführung" publisher="Springer Verlag" isbn="3540520430" year="1991"/>
    <outline text="Abrahams, Paul W." author="Paul W. Abrahams" title="Tex for the Impatient" publisher="Addison-Wesley Pub Co" isbn="0201513757" year="2000"/>
  </outline>
  <outline text="B">
    <outline text="Bach, Fred" author="Fred Bach" title="UNIX Handbuch zur Programmentwicklung" publisher="Hanser Fachbuchverlag" isbn="3446151036"/>
    <outline text="Bach, Maurice J." author="Maurice J. Bach" title="Design of the UNIX Operating System" publisher="Prentice Hall PTR" isbn="0132017997" year="1986"/>
  </outline>
</body>

...生成了想要的结果:

<list>
  <books text="A">
    <book>
      <text>Abelson, Harold</text>
      <author>Harold Abelson</author>
      <title>Struktur und Interpretation von Computerprogrammen.
        Eine Informatik-Einführung</title>
      <publisher>Springer Verlag</publisher>
      <isbn>3540520430</isbn>
      <year>1991</year>
    </book>
    <book>
      <text>Abrahams, Paul W.</text>
      <author>Paul W. Abrahams</author>
      <title>Tex for the Impatient</title>
      <publisher>Addison-Wesley Pub Co</publisher>
      <isbn>0201513757</isbn>
      <year>2000</year>
    </book>
  </books>
  <books text="B">
    <book>
      <text>Bach, Fred</text>
      <author>Fred Bach</author>
      <title>UNIX Handbuch zur Programmentwicklung</title>
      <publisher>Hanser Fachbuchverlag</publisher>
      <isbn>3446151036</isbn>
    </book>
    <book>
      <text>Bach, Maurice J.</text>
      <author>Maurice J. Bach</author>
      <title>Design of the UNIX Operating System</title>
      <publisher>Prentice Hall PTR</publisher>
      <isbn>0132017997</isbn>
      <year>1986</year>
    </book>
  </books>
</list>

答案 2 :(得分:3)

更短,更完整的解决方案:

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

 <xsl:template match="/*"><list><xsl:apply-templates/></list></xsl:template>

 <xsl:template match="outline">
    <books text="{@text}">
      <xsl:apply-templates/>
    </books>
  </xsl:template>

  <xsl:template match="outline/outline">
    <book><xsl:apply-templates select="@*"/></book>
  </xsl:template>

  <xsl:template match="outline/outline/@*">
      <xsl:element name="{name()}">
        <xsl:value-of select="." />
      </xsl:element>
  </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<body>
  <outline text="A">
    <outline text="Abelson, Harold" author="Harold Abelson" title="Struktur und Interpretation von Computerprogrammen. Eine Informatik-Einführung" publisher="Springer Verlag" isbn="3540520430" year="1991"/>
    <outline text="Abrahams, Paul W." author="Paul W. Abrahams" title="Tex for the Impatient" publisher="Addison-Wesley Pub Co" isbn="0201513757" year="2000"/>
  </outline>
  <outline text="B">
    <outline text="Bach, Fred" author="Fred Bach" title="UNIX Handbuch zur Programmentwicklung" publisher="Hanser Fachbuchverlag" isbn="3446151036"/>
    <outline text="Bach, Maurice J." author="Maurice J. Bach" title="Design of the UNIX Operating System" publisher="Prentice Hall PTR" isbn="0132017997" year="1986"/>
  </outline>
</body>

产生了想要的正确结果:

<list>
 <books text="A">
   <book>
      <text>Abelson, Harold</text>
      <author>Harold Abelson</author>
      <title>Struktur und Interpretation von Computerprogrammen. Eine Informatik-Einführung</title>
      <publisher>Springer Verlag</publisher>
      <isbn>3540520430</isbn>
      <year>1991</year>
   </book>
   <book>
      <text>Abrahams, Paul W.</text>
      <author>Paul W. Abrahams</author>
      <title>Tex for the Impatient</title>
      <publisher>Addison-Wesley Pub Co</publisher>
      <isbn>0201513757</isbn>
      <year>2000</year>
   </book>
 </books>
 <books text="B">
   <book>
      <text>Bach, Fred</text>
      <author>Fred Bach</author>
      <title>UNIX Handbuch zur Programmentwicklung</title>
      <publisher>Hanser Fachbuchverlag</publisher>
      <isbn>3446151036</isbn>
   </book>
   <book>
      <text>Bach, Maurice J.</text>
      <author>Maurice J. Bach</author>
      <title>Design of the UNIX Operating System</title>
      <publisher>Prentice Hall PTR</publisher>
      <isbn>0132017997</isbn>
      <year>1986</year>
   </book>
 </books>
<list>

<强>解释

  1. 正确使用模板和匹配模式。

  2. 正确使用 <xsl:element>


  3. <强> II。如果需要生成元素的特定顺序(因为无法保证源属性的顺序),请使用此轻微修改:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:template match="/*"><list><xsl:apply-templates/></list></xsl:template>
    
     <xsl:template match="outline">
        <books text="{@text}">
          <xsl:apply-templates/>
        </books>
      </xsl:template>
    
      <xsl:template match="outline/outline">
        <book>
          <xsl:apply-templates select="@*">
            <xsl:sort data-type="number" select=
              string-length(substring-before('text|author|title|publisher|isbn|year',name()))"/>
          </xsl:apply-templates></book>
      </xsl:template>
    
      <xsl:template match="outline/outline/@*">
          <xsl:element name="{name()}">
            <xsl:value-of select="." />
          </xsl:element>
      </xsl:template>
    </xsl:stylesheet>