Combining documents while saving xsi: type

I have 2 Document objects with documents that contain similar XML. For instance:

<tt:root xmlns:tt="http://myurl.com/">
  <tt:child/>
  <tt:child/>
</tt:root>

And another:

<ns1:root xmlns:ns1="http://myurl.com/" xmlns:ns2="http://myotherurl.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ns1:child/>
  <ns1:child xsi:type="ns2:SomeType"/>
</ns1:root>

I need to combine them into one document with 1 root element and 4 child elements. The problem is that if I use a function document.importNodefor merging, it correctly processes namespaces everywhere BUT xsi: type element. So, I get the result:

<tt:root xmlns:tt="http://myurl.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <tt:child/>
  <tt:child/>
  <ns1:child xmlns:ns1="http://myurl.com/"/>
  <ns1:child xmlns:ns1="http://myurl.com/" xsi:type="ns2:SomeType"/>
</tt:root>

As you can see, ns2 is used in xsi:type, but not defined anywhere. Is there any automated way to solve this problem?

Thank.

ADDED:

If this task cannot be completed using the standard DOM java libraries, maybe there is some other library that I can use to complete my task?

+5
6

XQuery : node, , :

declare variable $other external; element {node-name(*)} {*/*, $other/*/*}

XQuery ( , XQuery 1.0), copy-namespaces , .

XQuery , saxon9he.jar " xml", .

, , s9api API:

import javax.xml.parsers.DocumentBuilderFactory;
import net.sf.saxon.s9api.*;
import org.w3c.dom.Document;

...

  Document merge(Document context, Document other) throws Exception
  {
    Processor processor = new Processor(false);
    XQueryExecutable executable = processor.newXQueryCompiler().compile(
      "declare variable $other external; element {node-name(*)} {*/*, $other/*/*}");
    XQueryEvaluator evaluator = executable.load();    
    DocumentBuilder db = processor.newDocumentBuilder();
    evaluator.setContextItem(db.wrap(context));
    evaluator.setExternalVariable(new QName("other"), db.wrap(other));
    Document doc =
      DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
    processor.writeXdmValue(evaluator.evaluate(), new DOMDestination(doc));
    return doc;
  }
+1

( "xsi" ), ; , , (vanilla Java 64- Windows build 1.6.0_24).

String s1 = "<!-- 1st XML document here -->";
String s2 = "<!-- 2nd XML document here -->";

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware( true );
DocumentBuilder builder = factory.newDocumentBuilder();

Document doc1 = builder.parse( new ByteArrayInputStream( s1.getBytes() ) );
Document doc2 = builder.parse( new ByteArrayInputStream( s2.getBytes() ) );

Element doc1root = ( Element )doc1.getDocumentElement();
Element doc2root = ( Element )doc2.getDocumentElement();

NamedNodeMap atts1 = doc1root.getAttributes();
NamedNodeMap atts2 = doc2root.getAttributes();

for( int i = 0; i < atts1.getLength(); i++ )
{
    String name = atts1.item( i ).getNodeName();
    if( name.startsWith( "xmlns:" ) )
    {
        if( atts2.getNamedItem( name ) == null )
        {
            doc2root.setAttribute( name, atts1.item( i ).getNodeValue() );
        }    
    }    
}

NodeList nl = doc1.getDocumentElement().getChildNodes();
for( int i = 0; i < nl.getLength(); i++ )
{
    Node n = nl.item( i );
    doc2root.appendChild( doc2.importNode( n, true ) );

}

TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
StreamResult streamResult = new StreamResult( System.out );
transformer.transform( new DOMSource( doc2 ), streamResult );
+2

; , -, Java DOM/XML. ,

  • xsi:type="prefix:value" xsi:type="{namespace}value". , . <xsi:type="ns2:SomeType" xsi:type="{http://myotherurl.com/}SomeType".
  • .
  • 1. ; , .
+2

JAXB Mergeable plugin mergeFrom , . :

  • Unmarshal o1, o2
  • Marge o1, o2 o3
  • o3

JAXB xsi:type .

+1

UPDATE

, ( ).

. , :

<foo:root xmlns:foo="urn:ROOT">
    <foo:child xmlns:foo="urn:CHILD" xsi:type="foo:child-type">
       ...
    </foo:child>
</foo:root>

XML , "foo", . , :

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Demo {

    public static void main(String[] args) throws Exception  {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();

        File file1 = new File("src/forum231/input1.xml");
        Document doc1 = db.parse(file1);
        Element rootElement1 = doc1.getDocumentElement();

        File file2 = new File("src/forum231/input2.xml");
        Document doc2 = db.parse(file2);
        Element rootElement2 = doc2.getDocumentElement();

        // Copy Child Nodes
        NodeList childNodes2 = rootElement2.getChildNodes();
        for(int x=0; x<childNodes2.getLength(); x++) {
            Node importedNode = doc1.importNode(childNodes2.item(x), true);
            if(importedNode.getNodeType() == Node.ELEMENT_NODE) {
                Element importedElement = (Element) importedNode;
                // Copy Attributes
                NamedNodeMap namedNodeMap2 = rootElement2.getAttributes();
                for(int y=0; y<namedNodeMap2.getLength(); y++) {
                    Attr importedAttr = (Attr) doc1.importNode(namedNodeMap2.item(y), true);
                    importedElement.setAttributeNodeNS(importedAttr);
                }
            }
            rootElement1.appendChild(importedNode);
        }

        // Output Document
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();
        DOMSource source = new DOMSource(doc1);
        StreamResult result = new StreamResult(System.out);
        t.transform(source, result);
    }

}

<?xml version="1.0" encoding="UTF-8" standalone="no"?><tt:root xmlns:tt="http://myurl.com/">
  <tt:child/>
  <tt:child/>

  <ns1:child xmlns:ns1="http://myurl.com/" xmlns:ns2="http://myotherurl.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
  <ns1:child xmlns:ns1="http://myurl.com/" xmlns:ns2="http://myotherurl.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:SomeType"/>
</tt:root>

, . , :

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Demo {

    public static void main(String[] args) throws Exception  {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();

        File file1 = new File("input1.xml");
        Document doc1 = db.parse(file1);
        Element rootElement1 = doc1.getDocumentElement();

        File file2 = new File("input2.xml");
        Document doc2 = db.parse(file2);
        Element rootElement2 = doc2.getDocumentElement();

        // Copy Attributes
        NamedNodeMap namedNodeMap2 = rootElement2.getAttributes();
        for(int x=0; x<namedNodeMap2.getLength(); x++) {
            Attr importedNode = (Attr) doc1.importNode(namedNodeMap2.item(x), true);
            rootElement1.setAttributeNodeNS(importedNode);
        }

        // Copy Child Nodes
        NodeList childNodes2 = rootElement2.getChildNodes();
        for(int x=0; x<childNodes2.getLength(); x++) {
            Node importedNode = doc1.importNode(childNodes2.item(x), true);
            rootElement1.appendChild(importedNode);
        }

        // Output Document
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();
        DOMSource source = new DOMSource(doc1);
        StreamResult result = new StreamResult(System.out);
        t.transform(source, result);
    }

}

:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<tt:root xmlns:tt="http://myurl.com/" xmlns:ns1="http://myurl.com/" xmlns:ns2="http://myotherurl.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <tt:child/>
  <tt:child/>

  <ns1:child/>
  <ns1:child xsi:type="ns2:SomeType"/>
</tt:root>
+1

If you know that the namespace URI and the URI prefix you want to add can be as simple as adding an attribute to an element. This worked for me when my combined document was missing xmlns: xsd = "http://www.w3.org/2001/XMLSchema" contained in my imported document:

    myDocument.getDocumentElement.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
0
source

All Articles