xsl-list
[Top] [All Lists]

RE: Adding element to xml snippet using xslt

2005-02-22 15:49:19
I have to migrate the nodes from fileA(source doc) and fileB 
(which is 
also a xml doc) to an output xml doc. The xslt is run on 
fileA in such a 
manner that all nodes from fileA are copied over(preserving 
their order) 
and the common nodes that are present in fileA as well as fileB are 
merged using the xslt and the output of the merge is written to the 
output file.

In this particular case, 'drillOutDir' is present in fileB 
only, which 
needs to be also present in the ouput file too. The 'started' 
element is 
present in fileA as well as fileB, but its version in fileB 
is newer and 
hence i need to get the started element from fileB in my output file.

FileA contains --
<abc:configuration 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";  
xsi:schemaLocation="http://oracle.com/
xmlns/abcst/configuration configuration.xsd" locale="en" >
<started status="true"></started>
<server></server>
....
</abc:configuration>
-----------------------------

FileB contains --

<abc:configuration 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://oracle.com/ xmlns/abcst/configuration 
configuration.xsd" locale="en" >
<drillOutDir></drillOutDir>
<started status="true">This application was stopped.</started>
<server></server>
....
</abc:configuration>
------------------------------

Output file should contain --

<abc:configuration 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";  
xsi:schemaLocation="http://oracle.com/
xmlns/abcst/configuration configuration.xsd" locale="en" >
<drillOutDir></drillOutDir>
<started status="true">This application was stopped.</started>
<server></server>

....
</abc:configuration>

I've no idea what's in the "...." so I'll assume it doesn't exist.

It's not entirely clear to me what the general rules are: it's easy to do a
stylesheet that works for this example and then produces results you
consider wrong for the next example. What do you want to happen, for
example, if the status attribute is present in both documents but with
different values?

Here's a generic approach that uses XSLT 2.0 grouping.

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

<xsl:output indent="yes"/>
<xsl:template name="copy">
  <xsl:param name="group"/>
  <xsl:element name="{name($group[1])}">
    <xsl:copy-of select="$group/@*"/>
    <xsl:for-each-group select="$group/*" group-by="node-name(.)">
       <xsl:call-template name="copy">
         <xsl:with-param name="group" select="current-group()"/>
       </xsl:call-template>
    </xsl:for-each-group>
    <xsl:copy-of select="$group[1]/text()"/>
  </xsl:element>
</xsl:template>

<xsl:template name="main">
  <xsl:call-template name="copy">
    <xsl:with-param name="group" select="document(('a.xml', 'b.xml'))/*"/>
  </xsl:call-template>
</xsl:template>

</xsl:stylesheet>

Note this uses a named entry point, it doesn't have a principal source
document, this means that the two inputs are treated completely
symmetrically. It recurses down the tree in much the same way as a standard
apply-templates, but at each stage it passes a pair of elements, one from
each tree (if both exist) or a single element if it's present in one one
tree. It relies on the automatic elimination of duplicate attributes by the
XSLT processor. If two elements or attributes in the two documents have the
same name but different content, it outputs one of them, fairly arbitrarily.

To run this in Saxon 8.x:

java -jar saxon8.jar -it main test.xsl

This design is harder to realise in 1.0 because grouping is more difficult,
especially across two documents.

Note that there are no references to any elements in your source documents.
As far as I can tell from your description, the merging you want to achieve
is independent of the detailed structure of the XML, so a generic solution
is much preferable.

Michael Kay
http://www.saxonica.com/





--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--