Altova Mailing List Archives>Archive Index >microsoft.public.xsl Archive Home >Recent entries >Thread Prev - Re: Merge two XML docments with XSLT >Thread Next - Re: Merge two XML docments with XSLT Re: Merge two XML docments with XSLTTo: NULL Date: 9/11/2004 11:42:00 AM Hi Daniel, > This probably a dumb question but is > > <xsl:apply-templates select="@* | node()"/> > > The same as > > <xsl:apply-templates select="node()"/> > > Since node() gets all child nodes of any type? > No, not a dumb question - the terminology can get a little misleading. When you are taking about an XML DOM then 'node' means every component part of the document (much in the common sense of the word 'node'). But when you are talking about XPath then there are 3 different axis - the node axis, the attribute axis and the namespace axis. The node test node() only tests for items on the node axis - which are:- elements, text nodes, comments, processing instructions and that special one we call the document root node (not to be confused with the document root element). So, in short, no those two expressions are not the same... <xsl:apply-templates select="@* | node()"/> selects all nodes on the node axis (elements, text nodes, comments, pi's and doc root node) unioned with everything on the attribute axis. whereas... <xsl:apply-templates select="node()"/> only selects nodes on the node axis but no attributes. [from your other posting]... > What does this code segment do? > > <xsl:template match="@* | text() | comment() | > processing-instruction()"><!-- --> > <xsl:copy/><!-- Creates a copy of the current node (without child nodes > and attributes) --> > </xsl:template> > </xsl:stylesheet> > > It has no mode so im not sure how it is called by the other templates. If it > applies for all attributes, text, cmments and processing-instructions in the > souce document then what keeps it from over writing the work of the other > templates? It copies everything that was caught by that template - specifically, it copies all attributes, text nodes, comments and processing instructions that were caught by this template. Matched templates are not 'called' as such - they are matched against node-sets that are pushed out by an <xsl:apply-templates> (or <xsl:apply-imports>). You can imagine the <xsl:apply-templates> as something like throwing everything it selects up in the air - and the right templates will know which of those to catch. > what keeps it from over writing the work of the other templates? Because templates are matched based primarily on a 'best match' priority (there are other considerations too - but that will get far too complicated here). So a template that more specifically matches something will override a template that has a more 'generic' match. As a simple example, if you did... <xsl:apply-templates select="foo"/> and had two templates... <xsl:template match="*"> ... </xsl:template> <xsl:template match="foo"> ... </xsl:template> then it would be the second of those templates that would be applied - because it has a more specific match. > Is there anything else that needs to be done besides changing the maps > variable? > Would like to ensure that > - <top> is the root node of the resulting document > - <mapswithdata> wrapper is not in resulting document > - <maps> mapping data does not appear in the resulting document > - The root node of the resulting document remains <top> OK, 3 of those are more or less the same thing - ensuring that <top> is the document root element of the output. The other is ensuring that <mapswithdata> (and its children) does not appear in the output. You are dealing with a push processing stylesheet (push just means we are pushing nodes out for processing using <xsl:apply-templates> - as opposed to pulling nodes using <xsl:for-each>). The stylesheet is we already have is also based loosely on an idenity transform (an identity transform is one that, for the most part, copies the input document as is but with some exception alterations). Bearing this in mind - to perform almost any 'special' requirements is about adding an appropriate template that matches the node that is to have special processing and providing the logic that handles it. So, taking the first requirement - "ensure that <top> is the root node of the resulting document" - we need to catch whatever is the current input document root element and ensure that <top> is output instead, and then continue processing the rest of the document, e.g. adding a template that looks like... <xsl:template match="/*"> <top> <xsl:apply-templates/> </top> </xsl:template> and also ensuring that the <top> element is the document root element in the output. Well, we have already ensured that <top> is the document root element of the output - so we just need to ensure that the <top> element of the input document is not repeated in the output, e.g. <xsl:template match="top"> <xsl:apply-templates/> </xsl:template> Secondly, the requirement "ensure that <maps> mapping data does not appear in the resulting document" - again, it is a matter of adding a template that catches this element and prevents it being copied into the output, e.g. <xsl:template match="maps"/> (Note that the template tag is self-closing - so although the template will catch the <maps> element it is entirely empty so will do nothing further with that element). So the final stylesheet (hmmm, see also notes on .Net bug below) is as follows... <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:variable name="maps" select="/mapswithdata/maps/element"/> <xsl:template match="/"> <xsl:apply-templates/> </xsl:template> <xsl:template match="*"> <xsl:variable name="this-element-map" select="$maps[@source = local-name(current())]"/> <xsl:choose> <xsl:when test="$this-element-map"> <xsl:element name="{$this-element-map/@target}"> <xsl:apply-templates select="@*" mode="mapped"> <xsl:with-param name="attributes-map" select="$this-element-map/attribute"/> </xsl:apply-templates> <xsl:apply-templates/> </xsl:element> </xsl:when> <xsl:otherwise> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="/*"> <top> <xsl:apply-templates/> </top> </xsl:template> <xsl:template match="top"> <xsl:apply-templates/> </xsl:template> <xsl:template match="maps"/> <xsl:template match="@*" mode="mapped"> <xsl:param name="attributes-map"/> <xsl:variable name="this-attribute-map" select="$attributes-map[@source = local-name(current())]"/> <xsl:if test="$this-attribute-map"> <xsl:attribute name="{$this-attribute-map/@target}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:if> </xsl:template> <xsl:template match="@* | text() | comment() | processing-instruction()"> <xsl:copy/> </xsl:template> </xsl:stylesheet> OK, finally... > When I test this using saxon or the marrowsoft.com client it works, but when > I test it with C# System.Xml.Xsl.XslTransform it does not work. Is there > some modification that must be done to this to make it work w/ C# > System.Xml.Xsl.XslTransform? The part that I think is not getting processed > by the C# System.Xml.Xsl.XslTransform is <xsl:template match="@*" > mode="mapped"> Yes, you are right. There seems to be a bug in .Net casuing this stylesheet not to work as it would be expected. I haven't been able to come with with a shorter example that illustrates this bug - and I believe that something similar to this was reported recently on one of the newsgroups. Anyway, that is up to MS to determine the problem and get it fixed! I have even tried a few work arounds and all seem to fail with .Net! HTH Marrow http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger) http://www.topxml.com/Xselerator | ||||||
| Company | Legal | Press | Partners | Careers | Sitemap | Contact Us | Altova Blog | Mobile | Full Site | |||
|
