Empty xmlns = "" Attributes from Import

I am trying to do a conversion in an XML document. My XML conversion can lead to two different types of base element, depending on the value of a particular element:

<xsl:template match="/"> <xsl:choose> <xsl:when test="/databean/data[@id='pkhfeed']/value/text()='200'"> <xsl:call-template name="StructureA"> <xsl:with-param name="structure" select="//databean" /> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="StructureB"> <xsl:with-param name="structure" select="//databean" /> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> 

StructureA or StructureB are created with their own namespaces and schemaLocations:

 <StructureA xmlns="http://..."> 

StructureA and B have some common elements, so they are defined in a separate file called "xmlcommon.xslt", which includes templates in both structures. This xmlcommon file does not have a default namespace defined as I want it to be used from the namespace defined in StructureA or StructureB. But when I start my conversion, any templates extracted from the shared file result in empty xmlns attributes:

 <StructureA xmlns="http://..."> <SharedElement xmlns="">Something</SharedElement> </StructureA> 

When validating, an empty namespace is used instead of the correct parent. Does anyone know how I can stop my templates in my shared file by adding these pure xmlns attributes?

Here is a snippet from a shared file:

 <xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template name="ControlledListStructure"> <xsl:param name="xmlElem" /> <xsl:param name="structure" /> <xsl:element name="{$xmlElem}"> <!-- Blah blah blah --> </xsl:element> </xsl:template> </xsl:stylesheet> 
+4
source share
1 answer

The main thing is to understand that your stylesheet defines the name of each element that is added to the resulting tree. The element name consists of two parts: the local name and the namespace URI. In the above code, you specify the local name (the value is $xmlElem ), but you do not specify the namespace URI, which means that by default it will contain an empty string. (In fact, this takes up the default namespace for this style sheet module, since it is not there, then this is an empty string.) In other words, the element will not be in the namespace. When serializing a document, the XSLT processor must include xmlns="" un-declarations in order to decompress the default namespace that appears at the top. Otherwise, the element will occupy this namespace, which does not match your type. The least intrusive way to do this would be to add another parameter (e.g. $namespaceURI ), like you have with $xmlElem . Then you should write:

 <xsl:element name="{$xmlElem}" namespace="{$namespaceURI}"> 

Now the resulting element will take on whatever namespace you tell it (which will remove these default declarations for the namespace).

This should answer your question. I offer the following as a free bonus material .; -)

You must remove the text() node test in the comparison of values. Very rarely, you will need to directly compare the values ​​of text nodes. Instead, you can simply compare the string value of the element itself (which is defined as the concatenation of the string values ​​of all its streaming text nodes). It will look like this:

 <xsl:when test="/databean/data[@id='pkhfeed']/value = '200'"> 

The advantage of this method is that your code will not break if a comment is hidden there:

 <value>2<!--test-->00</value> 

In this case, there are two text nodes ("2" and "00"). Your original test will not work, as it checks to see if any of them match "200". In this case, it is unlikely to happen, but in any case, testing the string value of an element (in contrast to its node children text) is good practice when this is your intention.

Finally, I recommend that you learn about pattern rules and XPath context. I try to avoid <xsl:choose> , <xsl:call-template> and <xsl:with-param> whenever possible. First, template rules can help you avoid the many ugly, detailed parts of XSLT.

 <xsl:template match="/databean[data[@id='pkhfeed']/value = '200']" priority="1"> <StructureA xmlns="http://..."> ... </StructureA> </xsl:template> <xsl:template match="/databean"> <StructureB xmlns="http://..."> ... </StructureB> </xsl:template> 

Even if you continue to use <xsl:call-template> , you do not need to pass this parameter to $structure , as the current node will remain unchanged in the called template. You can access the //databean (or /databean , which I suspect is what you mean) as easily as in any of your StructureA or StructureB templates, since the current node will still be "/" (document node).

If you are interested in learning more about the XSLT core processing model and its most powerful features (template rules), I recommend that you check out β€œHow XSLT Works” , the chapter of a free sample from my Pocket XSLT 1.0 Pocket Reference.

I hope it was useful to you, even if it is more than you expected!

+9
source

All Articles