复制xslt中不存在的其他元素应用模板

时间:2013-07-26 18:37:05

标签: xml xslt

我是xslt的新手,面临一个问题。我必须使用xslt根据预定义的顺序重新排序xml文件中的元素。通过使用xsl:copy-of或xsl:apply-template并重新排序元素,我成功地完成了这项工作。但是,如果源xml具有xslt应用模板中不存在的一些新元素,则这些新元素根本不会被复制。如下例所示,元素'State'在输出中丢失。

例如。原始xml

<Company>
  <Employee id="100" Name="John" >
    <Salary value="15000"/>
    <Qualification text="Engineering">
    <State name="Kerala" code="02">
    <Background text="Indian">
  </Employee>
</Company>

以资格,薪资和背景的顺序重新排序元素的XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output indent="yes"  omit-xml-declaration="yes" method="xml" />
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="Employee">
    <xsl:copy>
      <xsl:apply-templates select="Qualification"/>
      <xsl:apply-templates select="Salary" />
      <xsl:apply-templates select="Background"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

获得的输出

<?xml version="1.0" encoding="utf-8"?>
<Company>
  <Employee>
    <Qualification text="Engineering" />
    <Salary value="15000" />
    <Background text="Indian" />
  </Employee>
</Company>

需要输出

<?xml version="1.0" encoding="utf-8"?>
<Company>
  <Employee>
    <Qualification text="Engineering" />
    <Salary value="15000" />
    <Background text="Indian" />
    <State name="Kerala" code="02"/>
  </Employee>
</Company>

请告诉我xslt如何在重新排序现有标签后自动复制任何剩余的新标签。

1 个答案:

答案 0 :(得分:3)

  <xsl:template match="Employee">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="Qualification"/>
      <xsl:apply-templates select="Salary" />
      <xsl:apply-templates select="Background"/>
      <xsl:apply-templates select="node()[
         not(self::Qualification | self::Salary | self::Background)]" />
    </xsl:copy>
  </xsl:template>

这将首先复制属性,然后复制您在固定顺序中感兴趣的特定元素,最后复制其他所有这三个元素。如果您要复制apply-templates代码而不其属性,请忽略第一个@*Employee)。

编辑:您在评论中说,即使在重新订购之后,您仍希望将任何评论保留在与其相关的元素之上。我能想到的最有效的方法是使用。在样式表的顶层(在任何模板之外)定义它:

<xsl:key name="elementPreamble" match="text()|comment()|processing-instruction()"
      use="generate-id(following-sibling::*[1])" />

给定任何元素节点,这提供了一种方法来有效地提取在此元素的开始标记和之前的元素的结束标记之间出现的所有非元素节点(或此元素的开始标记及其父开始标记,如果这是其父级的第一个子元素)。然后样式表变为:

<?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"  omit-xml-declaration="yes" method="xml" />
  <xsl:strip-space elements="*"/>

  <xsl:key name="elementPreamble" match="text()|comment()|processing-instruction()"
        use="generate-id(following-sibling::*[1])" />

  <xsl:template match="/">
    <!-- Only process the root _element_, not any root-level comments etc.
         Without this template any comments ahead of the root element would be
         doubled in the output -->
    <xsl:apply-templates select="*" />
  </xsl:template>

  <xsl:template match="@*|text()|comment()|processing-instruction()">
    <xsl:copy/>
  </xsl:template>

  <xsl:template match="*">
    <!-- any preamble for this element -->
    <xsl:apply-templates select="key('elementPreamble', generate-id())" />
    <xsl:copy>
      <xsl:apply-templates select="@* | *" />
      <!-- any "post-amble" between the last child element (if any) and this
           element's own closing tag -->
      <xsl:apply-templates select="(text()|comment()|processing-instruction())[
           not(following-sibling::*)]" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Employee">
    <xsl:copy>
      <xsl:apply-templates select="Qualification"/>
      <xsl:apply-templates select="Salary" />
      <xsl:apply-templates select="Background"/>
      <!-- other elements -->
      <xsl:apply-templates select="*[
         not(self::Qualification | self::Salary | self::Background)]" />
      <!-- "post-amble" -->
      <xsl:apply-templates select="(text()|comment()|processing-instruction())[
           not(following-sibling::*)]" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

给出输入

<!-- Details of the company's employees -->
<Company>
  <Employee id="100" Name="John" >
    <!-- salary -->
    <!-- check this with HR -->
    <Salary value="15000"/>
    <Qualification text="Engineering"/>
    <!-- the employee's home state -->
    <State name="Kerala" code="02"/>
    <!-- the employee's background -->
    <Background text="Indian"/>
    <!-- this is the end of the record -->
  </Employee>
</Company>

此样式表生成输出

<!-- Details of the company's employees -->
<Company>
  <Employee>
    <Qualification text="Engineering"/>
    <!-- salary -->
    <!-- check this with HR -->
    <Salary value="15000"/>
    <!-- the employee's background -->
    <Background text="Indian"/>
    <!-- the employee's home state -->
    <State name="Kerala" code="02"/>
    <!-- this is the end of the record -->
  </Employee>
</Company>

注释仍然附加在它们最近的跟随元素上,其顺序与它们在输入文档中出现的顺序相同。