Subject: Re: [xsl] Merging two xml documents using xslt From: Mukul Gandhi <mukul_gandhi@xxxxxxxxx> Date: Fri, 4 Feb 2005 08:11:37 -0800 (PST) |
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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] Merging two xml documents usi, Jianyu Lai | Thread | RE: [xsl] Merging two xml documents, cknell |
RE: [xsl] Decimal precision, Jim Neff | Date | Re: [xsl] Matching a list of attrib, chris |
Month |