[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: Merging two xml documents using xslt

Subject: Re: Merging two xml documents using xslt
From: Mukul Gandhi <mukul_gandhi@xxxxxxxxx>
Date: Fri, 4 Feb 2005 08:11:37 -0800 (PST)
xpath select document
Hi Jianyu,
  Please try this XSL -

Assume, this stylesheet is named as main.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl">
   
   <xsl:output method="xml" indent="yes" />
   
   <xsl:variable name="updates"
select="document('updates.xml')" />
   
   <!-- store XPath values of all elements, of
source.xml in a variable -->
   <xsl:variable name="all-xpaths">     
     <xsl:for-each select="//*">
       <xpath>
         <xsl:call-template name="constructXPathExpr">
           <xsl:with-param name="node" select="." />
           <xsl:with-param name="xpath"
select="name(.)" />
         </xsl:call-template>
       </xpath>   
     </xsl:for-each>
   </xsl:variable>
   
   <!-- a template rule that will match to any element
node -->
   <xsl:template match="*">     
     <xsl:variable name="curr-node" select="." />
     <xsl:variable name="xpath-expr">
       <xsl:call-template name="constructXPathExpr">
         <xsl:with-param name="node" select="." />
         <xsl:with-param name="xpath" select="name(.)"
/>
       </xsl:call-template>
     </xsl:variable>
     <xsl:element name="{name()}">        
        <xsl:choose>
          <xsl:when test="$xpath-expr =
$updates/updates/elem/@xpath">
            <xsl:value-of
select="$updates/updates/elem[@xpath =
$xpath-expr]/@xvalue" />           
          </xsl:when>  
          <xsl:when test="not(*)">          
            <xsl:value-of select="text()" />          
      
          </xsl:when> 
          <xsl:otherwise>
            <!-- code to create xml node in source -->
            <xsl:for-each
select="$updates/updates/elem"> 
	       <xsl:if test="not(@xpath =
exsl:node-set($all-xpaths)/xpath)"> 
	          <xsl:variable name="temp" select="." />	   
                        
	          <xsl:variable name="check">
	             <xsl:for-each select="$curr-node//*">
	                <xsl:variable name="expr">
	                   <xsl:call-template
name="constructXPathExpr">
	    		     <xsl:with-param name="node" select="." />
	    		     <xsl:with-param name="xpath"
select="name(.)" />
	                   </xsl:call-template>
	                </xsl:variable>
	                <xsl:if
test="starts-with($temp/@xpath,$expr)">
	                  1
	                </xsl:if>
	             </xsl:for-each>
	          </xsl:variable> 
	          
	          <xsl:if test="not(contains($check,'1')) and
(substring-after(substring-after(@xpath,$xpath-expr),'/')
!= '')">	          
	    	     <xsl:call-template
name="constructXmlFragment">
	    	        <xsl:with-param name="path"
select="substring-after(substring-after(@xpath,$xpath-expr),'/')"
/>
	    	        <xsl:with-param name="value"
select="@xvalue" />
	    	     </xsl:call-template>
	    	  </xsl:if>
	      </xsl:if>  	   
           </xsl:for-each>            
         </xsl:otherwise>
        </xsl:choose>
        
        <xsl:apply-templates select="*" />            

     </xsl:element>     
   </xsl:template>

   <!-- a template to construct an XPath expression,
for a given node -->
   <xsl:template name="constructXPathExpr">
     <xsl:param name="node" />
     <xsl:param name="xpath" />
     
     <xsl:choose>       
       <xsl:when test="$node/parent::*">
         <xsl:call-template name="constructXPathExpr">
       	   <xsl:with-param name="node"
select="$node/parent::*" />
       	   <xsl:with-param name="xpath"
select="concat(name($node/parent::*),'/',$xpath)" />
         </xsl:call-template>
       </xsl:when>
       <xsl:otherwise>
         <xsl:value-of select="concat('/',$xpath)" />
       </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
   
   <!-- a template to generate a XML fragment -->
   <xsl:template name="constructXmlFragment">
     <xsl:param name="path" />
     <xsl:param name="value" />
     
     <xsl:choose>
       <xsl:when test="contains($path,'/')">
         <xsl:element
name="{substring-before($path,'/')}">           
             <xsl:call-template
name="constructXmlFragment">
               <xsl:with-param name="path"
select="substring-after($path,'/')" />
               <xsl:with-param name="value"
select="$value" />
             </xsl:call-template>         
         </xsl:element>
       </xsl:when>
       <xsl:otherwise>         
         <xsl:element name="{$path}">
	    <xsl:value-of select="$value" />
         </xsl:element>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
   
</xsl:stylesheet>

source.xml is -
<?xml version="1.0" encoding="UTF-8"?>
<employee>
  <name>
    <first>Bob</first>    
  </name>  
</employee>

Given updates.xml as -
<?xml version="1.0" encoding="UTF-8"?>
<updates>  
  <elem xpath="/employee/address/country" xvalue="USA"
/>
  <elem xpath="/employee/name/first" xvalue="Bill" /> 

</updates>

When the transformation is run as -
java net.sf.saxon.Transform source.xml main.xsl

The output received is -
<?xml version="1.0" encoding="UTF-8"?>
<employee>
   <address>
      <country>USA</country>
   </address>
   <name>
      <first>Bill</first>
   </name>
</employee>

I tested with some more test cases, by changing the
updates.xml as..
a) 
<?xml version="1.0" encoding="UTF-8"?>
<updates>  
  <elem xpath="/employee/address/country" xvalue="USA"
/>
  <elem xpath="/employee/name/first" xvalue="Bill" /> 
  <elem xpath="/employee/name/last" xvalue="Gates" />
</updates>

The output received is -
<?xml version="1.0" encoding="UTF-8"?>
<employee>
   <address>
      <country>USA</country>
   </address>
   <name>
      <last>Gates</last>
      <first>Bill</first>
   </name>
</employee>

b)
<?xml version="1.0" encoding="UTF-8"?>
<updates>  
  <elem xpath="/employee/id" xvalue="1" />
  <elem xpath="/employee/address/country" xvalue="USA"
/>
  <elem xpath="/employee/name/first" xvalue="Bill" /> 
  <elem xpath="/employee/name/last" xvalue="Gates" />
</updates>

The output received is -
<?xml version="1.0" encoding="UTF-8"?>
<employee>
   <id>1</id>
   <address>
      <country>USA</country>
   </address>
   <name>
      <last>Gates</last>
      <first>Bill</first>
   </name>
</employee>

c)
<?xml version="1.0" encoding="UTF-8"?>
<updates>    
  <elem xpath="/employee/organization"
xvalue="Microsoft" />  
  <elem xpath="/employee/address/country" xvalue="USA"
/>  
  <elem xpath="/employee/name/first" xvalue="Bill" /> 
  <elem xpath="/employee/name/last" xvalue="Gates" /> 

</updates>

The output received is -
<?xml version="1.0" encoding="UTF-8"?>
<employee>
   <organization>Microsoft</organization>
   <address>
      <country>USA</country>
   </address>
   <name>
      <last>Gates</last>
      <first>Bill</first>
   </name>
</employee>

Regards,
Mukul
  
--- Jianyu Lai <jlai@xxxxxxxx> wrote:

> Hi all,
> 
> I'm rather new to XSL. I am struggling trying to
> come up with an xslt to
> solve the following problem:
> 
> First I have the source xml that looks like this:
> <employee>
>   <name>
>     <first>Bob</first>
>   </name>
> </employee>
> 
> I have another xml (updates.xml) that contains
> information about how to
> update the above source. Notice that this
> updates.xml is dynamically
> generated, and its contents vary.
> 
> <updates>
>   <elem xpath="/employee/address/country"
> xvalue="USA" />
>   <elem xpath="/employee/name/first" xvalue="Bill"
> />
> </updates>
> 
> I want to write an xslt that reads information from
> updates.xml, and updates
> source.xml based on these criteria:
> - if xpath in updates.xml exist in source.xml,
> replace source xml node with
> xvalue;
> - otherwise, create xml node in source(recursively
> if necessary), with
> xvalue defined in updates.xml;
> 
> Basically here is the result xml that I need:
> <employee>
>   <name>
>     <first>Bill</first>
>   </name>
>   <address>
>     <country>USA</country>
>   </address>
> </employee>
> 
> Is this something that can be done by xslt? If so,
> could any one shed some
> light on this? Your help is greatly appreciated.
> 
> Jianyu Lai



		
__________________________________ 
Do you Yahoo!? 
Yahoo! Mail - Helps protect you from nasty viruses. 
http://promotions.yahoo.com/new_mail

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.