XSLT copy all and insert missing in a specific ord

2019-09-15 03:17发布

问题:

I need an XSLT transform that copies the whole input document to the output document, inserting elements in a specific order.

Specifically, I want to transform input XML of this general form

<Begin>
    <tag1>a</tag1>
    <tag2>b</tag2>
    <tag3>c</tag3>
    <tag4>d</tag4>
    <tag5>e</tag5>
</Begin>

to itself, but if the input has no /Begin/tag1 or /Begin/tag4then I want to provide one in the order given above. That is, I want to transform

<Begin>
    <tag2>b</tag2>
    <tag3>c</tag3>
    <tag5>e</tag5>
</Begin>

to

<Begin>
    <tag1>a</tag1>
    <tag2>b</tag2>
    <tag3>c</tag3>
    <tag4>d</tag4>
    <tag5>e</tag5>
</Begin>

I asked a related question to this XSLT copy all and replace on conditions with a thought of extrapolating the solution to big number of nodes but I am unable to figure the solution to the above problem.

回答1:

What you are now asking is doable, but it does not afford quite as tidy a solution as does your previous question. Nevertheless, it is doable.

The approach that seems cleanest to me involves using <xsl:choose>, which in your previous question you remarked you had not been able to apply as specifically as you wanted. As is usually the case with XSL, the key is to properly select the nodes to which each template applies. You don't want to add default children to every node, but rather only to <Begin> nodes. You might thus do this:

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

  <!-- by default, all nodes and attributes are copied verbatim to the output -->
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <!-- Begin elements are transformed differently: -->
  <xsl:template match="Begin">
    <!-- the element itself is copied, along with its attributes, if any -->
    <xsl:copy>
      <xsl:apply-templates select="@*" />

      <!-- each child, tag1 ... tagN, is copied if present or inserted
           if absent.  A separate choice must be made for each. -->
      <xsl:choose>
        <xsl:when test="tag1">
          <!-- will apply the identity transform, because there is no other
               template that matches: -->
          <xsl:apply-templates select="tag1" />
        </xsl:when>
        <xsl:otherwise>
          <tag1>x1</tag1>
        </xsl:otherwise>
      </xsl:choose>

      <xsl:choose>
        <xsl:when test="tag2">
          <xsl:apply-templates select="tag2" />
        </xsl:when>
        <xsl:otherwise>
          <tag2>x2</tag2>
        </xsl:otherwise>
      </xsl:choose>

      <!-- ... the same for tag3, tag4, tag5 ... -->

      <!-- no provision is herein made for any child nodes of Begin other than
           attributes and child elements tag1 ... tag5 -->
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>


标签: xml xslt