[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: Comparing direct ancestors
On Thu, May 24, 2012 at 4:40 PM, Spencer Tickner <spencertickner@xxxxxxxxx> wrote: > Hi List, > > Thanks in advance for any help. > > I've been banging my head around this problem for awhile now and could > use any advice anyone is willing to give. I have the following xml: > > <?xml version="1.0"?> > <root> > <change-begin/> > <a> > <p>Foo<change-end/></p> > </a> > <change-begin/> > <b> > <d> > <t>Bar</t> > </d> > <d> > <t>Foo</t> > </d> > </b> > <change-end/> > <p>Nothing <change-begin/>to worry<change-end/> about</p> > </root> > > I need to write an xslt (2.0 is fine) that will "move" the > <change-begin/> and <change-end/> elements to be children of the > nearest pre-defined allowable element. So in the example above I have > <p> and <t> as elements that allow the <change-begin/> and > <change-end/> elements. The output should look like this: > > <?xml version="1.0"?> > <root> > <a> > <p><change-begin/>Foo<change-end/></p> > </a> > <b> > <d> > <t><change-begin/>Bar</t> > </d> > <d> > <t>Foo<change-end/></t> > </d> > </b> > <p>Nothing <change-begin/>to worry<change-end/> about</p> > </root> > > My plan was a multi-pass stylesheet that first took care of the > <change-begin/> then went on to take care of the <change-ends/>. For > brevity I've limit this post to trying to deal with the > <change-begin/>: > <snip> > So far it doesn't work and is fast becoming a bunch of spaghetti > <choose> statements. If anyone has any ideas I would love to hear > them. > I've been experimenting with this to see how far I can get by applying Felleisen et al's Design recipe to XSLT. What follows is deliberately slow and methodical but it is a scalable approach for dealing with those complex problems. I'm sure somebody whose XPath is better than mine can take this all the way. Look at your input. It has the change-begin and the change-end elements in the wrong place. However if we took them out we are left with a skeleton where everything is in the write place. Let's do that. <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" exclude-result-prefixes=""> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- STEP ONE drop the change-begin and change-end elements copy everything else --> <xsl:template match="change-begin|change-end"/> </xsl:stylesheet> That gives us this. <?xml version="1.0" encoding="UTF-8"?><root> <a> <p>Foo </p> </a> <b> <d> <t>Bar</t> </d> <d> <t>Foo</t> </d> </b> <p>Nothing to worry about</p> </root> OK nothing is in the wrong place but some things that were in the write place have been removed (see the Nothing to worry about). STEP 2 - Put back the things that we removed but were in the right place. <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" exclude-result-prefixes=""> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- STEP ONE drop the change-begin and change-end elements copy everything else --> <xsl:template match="change-begin|change-end"/> <!-- STEP TWO put back the change-begin and the change elements that were wrongfully dropped from step one --> <xsl:template match="p/change-begin|p/change-end|t/change-begin|t/change-end"> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet> Now we have this. <?xml version="1.0" encoding="UTF-8"?><root> <a> <p>Foo<change-end/> </p> </a> <b> <d> <t>Bar</t> </d> <d> <t>Foo</t> </d> </b> <p>Nothing <change-begin/>to worry<change-end/> about</p> </root> Let's do the change-begin's first. What shall we add to what we already have that gets us closer to our goal. I tried this <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" exclude-result-prefixes=""> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- STEP ONE drop the change-begin and change-end elements copy everything else --> <xsl:template match="change-begin|change-end"/> <!-- STEP TWO put back the change-begin and the change elements that were wrongfully dropped from step one --> <xsl:template match="p/change-begin|p/change-end|t/change-begin|t/change-end" priority="2"> <xsl:copy-of select="."/> </xsl:template> <!-- STEP 3 Pull in preceding orphan change-begins to the allowable element --> <!-- Changed the preceding template rule to priority 2 to overcome ambiguous rule --> <xsl:template match="p[preceding::change-begin] | t[preceding::change-begin]"> <xsl:copy> <xsl:copy-of select="preceding::change-begin[1]"/> <xsl:apply-templates/> </xsl:copy> </xsl:template> This gives us <?xml version="1.0" encoding="UTF-8"?><root> <a> <p><change-begin/>Foo<change-end/> </p> </a> <b> <d> <t><change-begin/>Bar</t> </d> <d> <t><change-begin/>Foo</t> </d> </b> <p><change-begin/>Nothing <change-begin/>to worry<change-end/> about</p> </root> which is close but not quite right because the same change-begin has been copied into more than one allowable element <t><change-begin/>Bar</t> and <t><change-begin/>Foo</t> Perhaps someone whose XPath is sharper than mine can fix that bit, what is required is that an allowable element should only consume an orphan <change-begin> if it's path to it along the preceding axis is not blocked by another allowable element. Analagous arguments apply to <change-end> along the following axis. Note we have stayed within the realm of XSLT 1 </xsl:stylesheet> Close, but not quite.
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|