Search code examples
androidxpathappendchilddomexception

android XPath, copy nodes from one document to another


Hi I need to copy nodes from one XML into another one:

String _sPathOfrObj = "/response/grp/ofr/obj";
String _sPathHotelData = "/main/hotelData";
String _sPathStatus = "/main/status";
xpath.reset();
NodeList status = (NodeList) xpath.evaluate( _sPathStatus, details, XPathConstants.NODESET );
if(status.item( 0 ).getTextContent().equalsIgnoreCase( "ok" ))
{
    NodeList nodes3 = (NodeList) xpath.evaluate( _sPathOfrObj, result, XPathConstants.NODESET );
    NodeList nodes4 = (NodeList) xpath.evaluate( _sPathHotelData, details, XPathConstants.NODESET);
    minimum = Math.min( nodes3.getLength(), nodes4.getLength() );

    Log.i(CLASS_NAME, "obj="+nodes3.getLength());
    Log.i(CLASS_NAME, "hdat="+nodes4.getLength());

    for (i = 0; i < minimum; i++)
    {
        try
        {
            nodes3.item( i ).appendChild( nodes4.item( i ) );
        }
        catch(DOMException dome)
        {
            dome.printStackTrace();
            Log.e(CLASS_NAME, dome.code+"" );
        }
    }
}

but it generates an error, DOMException WRONG_DOCUMENT_ERR or when I will do nodes4.item( i ).deepClone(true or false) it will throw DOMException NAMESPACE_ERR

Is there a way to do it?

Many thanks


Solution

  • I've managed to have it working, it is a mixture of my solution to overcome deepClone throwing NAMESPACE_ERR and the solution presented in the link.

    Basically I wasn't able to make a copy of the given node without an error so I am flattening the XML to string and converting the string to new Node and by using the adoptNode I have my solution:)

    I do realise that it is hell of a hack but it works for my tight deadline:)

    The converting to string is done by using Transformer class as follows:

    private static final String CLASS_NAME = "SendQueryTask";
    //...
    import java.io.StringWriter;
    
    import javax.xml.transform.OutputKeys;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerConfigurationException;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.TransformerFactoryConfigurationError;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    //...
    private String transformXmlToString(Node node)
    {
        Transformer transformer = null;
        try
        {
            transformer = TransformerFactory.newInstance().newTransformer();
        }
        catch (TransformerConfigurationException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (TransformerFactoryConfigurationError e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if ( transformer != null )
        {
            transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
    
            // initialize StreamResult with File object to save to file
            StreamResult result = new StreamResult( new StringWriter() );
            DOMSource source = new DOMSource( node );
    
            try
            {
                transformer.transform( source, result );
            }
            catch (TransformerException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            String xmlString = result.getWriter().toString();
            Log.i( CLASS_NAME, "flattened=" + (xmlString) );
    
            return xmlString;
        }       
        return null;
    }
    

    and to convert it back to Node

    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import org.apache.http.protocol.HTTP;
    import java.io.UnsupportedEncodingException;
    
    private Node dumbNodeCopy(Node item)
    {
        String xmlString = transformXmlToString( item );
    
        if ( xmlString != null )
        {
            InputStream is = null;
            try
            {
                is = new ByteArrayInputStream( xmlString.getBytes( HTTP.UTF_8 ) );
            }
            catch (UnsupportedEncodingException e)
            {
                e.printStackTrace();
            }
    
            if ( is != null )
            {
                Document doc = null;
                dbf = DocumentBuilderFactory.newInstance();
                try
                {
                    db = dbf.newDocumentBuilder();
                    doc = db.parse( is );
                    doc.getDocumentElement().normalize();
    
                }
                catch (ParserConfigurationException e)
                {
                    e.printStackTrace();
                }
                catch (SAXException e)
                {
                    e.printStackTrace();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
    
                if ( doc != null ) return doc.getFirstChild();
            }
            return null;
        }
        return null;
    

    and finally the copying

    NodeList nodes3 = (NodeList) xpath.evaluate( _sPathOfrObj, result,
            XPathConstants.NODESET );
    NodeList nodes4 = (NodeList) xpath.evaluate( _sPathHotelData, details,
            XPathConstants.NODESET );
    minimum = Math.min( nodes3.getLength(), nodes4.getLength() );
    
    Log.i( CLASS_NAME, "obj=" + nodes3.getLength() );
    Log.i( CLASS_NAME, "hdat=" + nodes4.getLength() );
    
    for (i = 0; i < minimum; i++)
    {
        try
        {
            Node copy = dumbNodeCopy( nodes4.item( i ) );
            if ( copy != null )
            {
                // nodes3.item( i ).appendChild( copy );
                nodes3.item( i ).appendChild(
                        nodes3.item( i ).getOwnerDocument().adoptNode( copy ) );
            }
            else
                Log.e( CLASS_NAME, "Copy of nodes4#" + i + ", failed." );
        }
        catch (DOMException dome)
        {
            dome.printStackTrace();
            Log.e( CLASS_NAME, dome.code + "" );
        }
    }
    

    btw. don't laugh at the code:-) I know that it looks terrible but my imperative ATM is to meet deadlines, and if anyone will propose neat solution I will happily adhere:)