The namespace nodes of the XML data do not actually read the namespace nodes from the parent element, but each element has its own namespace nodes. So just adding a new default namespace to the root element does not work, but leads to a document like this
<root xmlns="namespaceURL"> <child xmlns=""/> ... </root>
Note the appearance of the default empty namespace xmlns="" for the child element (s). What you need to do is change the namespace of each node or create a new document with the required default namespace and copy the contents, elements and attribute names, etc. Old document to new. This can be done by recursively traversing the source document. With a Java DOM implementation, this can be time consuming, I heard. One short cut can be reading a document using the DOM with a namespace, and then adding a new default namespace as an attribute. Another solution is to change the namespace using the XSLT transform, which seems quite appropriate in this case, since you are actually already generating the result using the XSLT transform.
Use this XSLT stylesheet to add a new default namespace and layout to the root element. This style sheet retains the old namespace, but adds all the elements to the new default namespace if they were not previously in the namespace.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:variable name="ns" select="'namespaceURL'"/> <xsl:variable name="schemaLoc" select="'namespaceURL pathToMySchema.xsd'"/> <xsl:template match="/*" priority="1"> <xsl:element name="{local-name()}" namespace="{$ns}"> <xsl:attribute name="xsi:schemaLocation" namespace="http://www.w3.org/2001/XMLSchema-instance"> <xsl:value-of select="$schemaLoc"/> </xsl:attribute> <xsl:apply-templates select="@* | node()"/> </xsl:element> </xsl:template> <xsl:template match="*[namespace-uri() = '']"> <xsl:element name="{local-name()}" namespace="{$ns}"> <xsl:apply-templates select="@* | node()"/> </xsl:element> </xsl:template> <xsl:template match="*[not(namespace-uri() = '')]"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Instead of creating a transformer with
Transformer trans = transfac.newTransformer();
(which creates a stylesheet that performs the same conversion), create an XSLT input source and give it as parameter newTransformer()
javax.xml.transform.Source xsltSource = new javax.xml.transform.stream.StreamSource(xsltFile); Transformer trans = transFact.newTransformer(xsltSource);
where xsltFile is a File object pointing to this XSLT file.
Set the output properties as you like and call transform() , as in your code example. The result should be what you need, but I have not tested this in Java . This XSLT file is checked for some trivial cases, and there is sample input and output at the end of this answer.
Some minor notes:
- In this process, the original document object is not changed. The new default namespace appears only at the output of the
transform() method. - The namespace prefix for the namespace of the schema instance is usually
xsi: rather than xs: as in your code example ( xs: used in schema definitions (as well as xsd: ).
Sample input and output for the XSLT stylesheet shown above
Input:
<root> <child>text</child> <child attribute="attr-value"/> <?pi-target pi-content?> <nsx:ns-child xmlns:nsx="ns1x"> <no-ns-child>text</no-ns-child> <nsx:ns-child nsx:ns-attribute="nsx-attr-value">text</nsx:ns-child> </nsx:ns-child> <defns-child xmlns="default-ns"> <def-child attr="val">text</def-child> <child xmlns=""/> </defns-child> <child>text</child> </root>
Output:
<?xml version="1.0" encoding="UTF-8"?> <root xmlns="namespaceURL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="namespaceURL pathToMySchema.xsd"> <child>text</child> <child attribute="attr-value"/> <?pi-target pi-content?> <nsx:ns-child xmlns:nsx="ns1x"> <no-ns-child>text</no-ns-child> <nsx:ns-child nsx:ns-attribute="nsx-attr-value">text</nsx:ns-child> </nsx:ns-child> <defns-child xmlns="default-ns"> <def-child attr="val">text</def-child> <child xmlns="namespaceURL"/> </defns-child> <child>text</child> </root>