![]() |
|
|
|||||||
![]() |
XML - Identity transformation problems |
|
|
Thread Tools | Search this Thread |
|
|
#1 |
|
Hello,
I'm attempting to "populate" an template XML file with some data using identity transform (approach suggested by Joe K.; Thanks! come across some strange behaviour using XMLSpy, AltovaXML, and xsltproc. The actual stylesheets are to be auto-generated by another stylesheet (that process I've worked out! these generated stylesheets in XMLSpy's XSL debugger. So I'm wondering if my approach is basically wrong to elicit the unexpected behaviour, rather than that the apps are buggy. So here goes: The transformation stylesheet is: <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns <xsl:template match="/message/Control/Trace/Id"> <xsl:attribute name="extension">bbb-999</xsl:attribute> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> nothing fancy except that I'm trying to put/add value to the "/message/Control/Trace/Id/@extension" attribute and the xml to be transformed is: <?xml version="1.0" encoding="ISO-8859-1"?> <message> <id>Text</id> <creationTime>Text</creationTime> <versionCode/> <Id>Text</Id> <processingCode/> <processingModeCode/> <acceptCode/> <commRcv> <device> <id extension="Old_Ext">Text</id> </device> </commRcv> <commSnd> <device> <id>Text</id> </device> </commSnd> <Control> <author> <Entity> <id>Text</id> <code/> <Organization> <id>Text</id> </Organization> </Entity> </author> <Trace> <Id extension="OLD">Text</Id> <person> <value/> <Text>String</Text> </person> <birthTime> <value>Text</value> <Text>String</Text> </birthTime> <name> <value>Text</value> <Text>String</Text> </name> </Trace> </Control> </message> I'm unsure if I am doing anything illegal as far as XSL/T etc. is concerned but here are the results: XMLSpy + AltovaXML add the attribute to /message/Control/Trace instead, and the /message/Control/Trace/Id element isn't created at all. xsltproc: Gives the error "xsl:attribute: Cannot add attributes to an element if children have been already added to the element." That is very odd since the /message/Control/Trace/Id/ element doesn't have any children! I've tried various permutations of the stylesheet as follows: Trial #1: Populate attribute & element <xsl:attribute name="extension">bbb-999</xsl:attribute> <xsl:elementname="Id">xsl-123456789</xsl:element> XMLSpy/AltovaXML add the extension to the parent /message/Control/Trace element and the "Id" element isn't created. xsltproc errors as before. Trial #2: Populate element & attribute <xsl:elementname="Id">xsl-123456789</xsl:element> <xsl:attribute name="extension">bbb-999</xsl:attribute> XMLSpy/AltovaXML add/populate the "Id" element correctly but the "extension" attribute is missing. xsltproc errors as before. Trial #3: Populate element <xsl:elementname="Id">xsl-123456789</xsl:element> Value for "Id" element is add without problem by all. Trial #4: Two seperate templates This was my original approach but didn't work (see below). Created two seperate template, one for the element and one for the attribute: <xsl:template match="/message/Control/Trace/Id/@extension"> <xsl:attribute name="extension">bbb-999</xsl:attribute> </xsl:template> <xsl:template match="/message/Control/Trace/Id"> <xsl:element name="queryId">xsl-123456789</xsl:element> </xsl:template> The template for the "Id" element is actioned while the one for the "Id/@extension" attribute never is; unsure why the xslt processor never 'runs' the template for the So what am I doing wrong??? Is there a better/proper way to populate both the element and its attribute? Would aoppreciate any suggestions! Regards, Bilal B. *** Sent via Developersdex http://www.developersdex.com *** Bilal |
|
|
|
|
#2 |
|
Posts: n/a
|
Bilal wrote: > <xsl:template match="/message/Control/Trace/Id"> > <xsl:attribute name="extension">bbb-999</xsl:attribute> > </xsl:template> That does not work out, if you want to add an attribute to that element then you need to first copy the element <xsl:template match="/message/Control/Trace/Id"> <xsl:copy> <!-- use that if you have other attributes to copy --> <xsl:apply-templates select="@*"/> <xsl:attribute name="extension">bbb-999</xsl:attribute> <xsl:apply-templates/> </xsl:copy> </xsl:template> -- Martin Honnen http://JavaScript.FAQTs.com/ |
|
|
|
#3 |
|
Posts: n/a
|
Hi Martin,
Many thanks!! That works for adding/setting the attribute but what if the element's value is also being set simultaneously? Regards, Bilal *** Sent via Developersdex http://www.developersdex.com *** |
|
|
|
#4 |
|
Posts: n/a
|
Bilal wrote: > That works for adding/setting the attribute but what if > the element's value is also being set simultaneously? Well once you write a template for that element it is up to you to fill the template with instructions as needed, the xsl:copy will only copy the element itself, the <xsl:apply-templates select="@*"/> (and the other template you had) take care of copying existing attributes, the <xsl:attribute name="extension">bbb-999</xsl:attribute> adds the new attribute, and the <xsl:apply-templates/> lets the XSLT processor process the existing child nodes. If you don't want any of those steps then remove or replace them e.g. <xsl:template match="/message/Control/Trace/Id"> <xsl:copy> <!-- use that if you have other attributes to copy --> <xsl:apply-templates select="@*"/> <xsl:attribute name="extension">bbb-999</xsl:attribute> <xsl:text>Kibology for all</xsl:text> </xsl:copy> </xsl:template> will not process the child nodes but simply add that (example) text as a child node. -- Martin Honnen http://JavaScript.FAQTs.com/ |
|
|
|
#5 |
|
Posts: n/a
|
Hi Martin,
Thanks for the explanation and the example. Unfortunately, I still don't have a full understanding about the 'precedence' of how the templates are applied, and hence in my not-so-infiite wisdom, I was trying to use the code below (note the xsl:element tag instead of the xsl:text tag) to put value in the Id element itself, and kept on wondering why it was adding an new element /message/Control/Trace/Id/Id instead <xsl:template match="/message/Control/Trace/Id"> <xsl:copy> <!-- use that if you have other attributes to copy --> <xsl:apply-templates select="@*"/> <xsl:attribute name="extension">bbb-999</xsl:attribute> <xsl:element name="Id">Kibology for all</xsl:element> </xsl:copy> </xsl:template> Just to take this one step further, what would be the right way to copy the children below /message/Control/Trace/Id using the default template? <xsl:template match="/message/Control/Trace/Id"> <xsl:copy> <!-- use that if you have other attributes to copy --> <xsl:apply-templates select="@*"/> <xsl:attribute name="extension">bbb-999</xsl:attribute> <xsl:text>Kibology for all</xsl:text> <xsl:apply-templates /> </xsl:copy> </xsl:template> This appears to do the trick (I think) but what it ALSO does is copy the old text value (child?) AFTER inserting the new text value, as well as copying any remaining child elements. How would one achieve copying the new text value/child, avoid copying the old text value/child, but copy any child elements? Lastly, any recommendations on good XSL resources/books other then obvious ones on the web? I think I'm reaching the limits of my self-learned XSLT knowledge. Regards, Bilal B. *** Sent via Developersdex http://www.developersdex.com *** |
|
|
|
#6 |
|
Posts: n/a
|
Bilal wrote: > Unfortunately, I still > don't have a full understanding about the 'precedence' of how the > templates are applied, and hence in my not-so-infiite wisdom, I was > trying to use the code below (note the xsl:element tag instead of the > xsl:text tag) to put value in the Id element itself, and kept on > wondering why it was adding an new element /message/Control/Trace/Id/Id > instead > > <xsl:template match="/message/Control/Trace/Id"> You have a template here for Id elements with parent Trace with parent Control with parent message as the root element, then in that template you do > <xsl:copy> meaning that Id element is copied. If you don't want to copy those Id elements then don't use xsl:copy in this template. But if you want to have attributes like that extension attribute you first need an element to add it to. > How would one achieve copying the new text value/child, avoid copying > the old text value/child, but copy any child elements? Sorry, in my understanding you can't "copy" "new" values or children, "new" stuff can only be added. As for copying only child _elements_ but not child _text_ nodes simply do e.g. <xsl:apply-templates select="*"/> instead of <xsl:apply-templates/> in the template where you want to do that. For the rare case that you also have comment nodes or processing instruction nodes that need to be copied like the elements then do e.g. <xsl:apply-templates select="node()[self::* or self::comment() or self: -- Martin Honnen http://JavaScript.FAQTs.com/ |
|
|
|
#7 |
|
Posts: n/a
|
Bilal wrote:
> don't have a full understanding about the 'precedence' of how the > templates are applied There are almost no precedence rules, unfortunately. If you've got a possible conflict, you should probably make your precedence explicit by adding the priority attribute to the templates in question. > How would one achieve copying the new text value/child, avoid copying > the old text value/child, but copy any child elements? One solution: Change the select in the second apply-templates so it matches only elements. "*" will work, since the implied axis is child and the principal node type of that axis is element. If you wanted to accept other kinds of non-text nodes you might want to enhance that a bit, eg "*|comment()". Another solution would be to use a mode, but that's a bit more complicated to explain if you aren't already familiar with them. > Lastly, any recommendations on good XSL resources/books other then > obvious ones on the web? I think I'm reaching the limits of my > self-learned XSLT knowledge. I haven't looked at what's come out recently. Mike Kay's tome is still the best XSLT reference manual out there, I think, but if you're looking for a tutorial you'll want something else as well. -- () ASCII Ribbon Campaign | Joe Kesselman /\ Stamp out HTML e-mail! | System architexture and kinetic poetry |
|
|
|
#8 |
|
Posts: n/a
|
Hi Joe and Martin,
Thanks for the replies; your explanation/examples helped solve the problem I had been stuck! Many thanks! Regards, Bilal B. *** Sent via Developersdex http://www.developersdex.com *** |
|