将多分支XML文档转换为多个XML文档

时间:2015-10-22 11:54:29

标签: xslt xpath cap

我们需要制作多个XML文档,每个文档都有一个" info"元素,来自单个XML文档,其中包含未知数量的" info"元素。例如,本文档:

<alert>
  <identifier>2.49.0.1.124.76fea972.2015</identifier>  
  <info>
    <language>en</language>
  </info>
  <info>
    <language>fr</language>
  </info>
</alert>

应该产生这两个文件:

<alert>
  <identifier>2.49.0.1.124.76fea972.2015</identifier>  
  <info>
    <language>en</language>
  </info>
</alert>

<alert>
  <identifier>2.49.0.1.124.76fea972.2015</identifier>  
  <info>
    <language>fr</language>
  </info>
</alert>

修剪一个&#34; info&#34;的兄弟姐妹。我们需要复制所有祖先(到根)的所有节点,属性,命名空间等,以及特定&#34; info&#34;的所有节点,属性,命名空间等。元件。

我是XSLT的新手,不知道如何做到这一点。任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:1)

轻松xsh

my $orig := open file.xml ;
for my $info in /alert/info {
    my $clone := clone $orig ;
    my $i = count($info/preceding::info) ;
    delete $clone/alert/info[count(preceding::info) = $i] ;
    save :f concat('file', $i, '.xml') $clone ;
}

答案 1 :(得分:0)

使用像Saxon 9或AltovaXML或XmlPrime这样的XSLT 2.0处理器,你可以使用这样的方法:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

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

<xsl:template match="/">
  <xsl:apply-templates select="alert/info" mode="split"/>
</xsl:template>

<xsl:template match="info" mode="split">
  <xsl:result-document href="language-{language}.xml">
    <xsl:apply-templates select="/*">
      <xsl:with-param name="info" select="current()" tunnel="yes"/>
    </xsl:apply-templates>
  </xsl:result-document>
</xsl:template>

<xsl:template match="info">
  <xsl:param name="info" tunnel="yes"/>
  <xsl:if test=". is $info">
    <xsl:next-match/>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

如果输入位于某个名称空间中,则使用例如<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xpath-default-namespace="urn:oasis:names:tc:emergency:cap:1.2">

如果要独立于命名空间运行XSLT,请使用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

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

<xsl:template match="/">
  <xsl:apply-templates select="*:alert/*:info" mode="split"/>
</xsl:template>

<xsl:template match="*:info" mode="split">
  <xsl:result-document href="language-{language}.xml">
    <xsl:apply-templates select="/*">
      <xsl:with-param name="info" select="current()" tunnel="yes"/>
    </xsl:apply-templates>
  </xsl:result-document>
</xsl:template>

<xsl:template match="*:info">
  <xsl:param name="info" tunnel="yes"/>
  <xsl:if test=". is $info">
    <xsl:next-match/>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

答案 2 :(得分:0)

或许这比马丁的解决方案简单一点:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

<xsl:template match="/">
 <xsl:for-each select="alert/info">
  <xsl:result-document href="language-{language}.xml">
    <alert>
      <xsl:copy-of select="../identifier"/>
      <xsl:copy-of select="."/>
    </alert>
  </xsl:result-document>
 </xsl:for-each>
</xsl:template>

</xsl:stylesheet>