Example usage for org.w3c.dom Document renameNode

List of usage examples for org.w3c.dom Document renameNode

Introduction

In this page you can find the example usage for org.w3c.dom Document renameNode.

Prototype

public Node renameNode(Node n, String namespaceURI, String qualifiedName) throws DOMException;

Source Link

Document

Rename an existing node of type ELEMENT_NODE or ATTRIBUTE_NODE.

Usage

From source file:org.kuali.rice.krad.devtools.maintainablexml.MaintainableXMLConversionServiceImpl.java

private void transformClassNode(Document document, Node node)
        throws ClassNotFoundException, XPathExpressionException, IllegalAccessException,
        InvocationTargetException, NoSuchMethodException, InstantiationException {
    String className = node.getNodeName();
    if (this.classNameRuleMap.containsKey(className)) {
        String newClassName = this.classNameRuleMap.get(className);
        document.renameNode(node, null, newClassName);
        className = newClassName;/*from w  w w.  j a  v  a  2s  . co m*/
    }
    Class<?> dataObjectClass = Class.forName(className);
    if (classPropertyRuleMap.containsKey(className)) {
        transformNode(document, node, dataObjectClass, classPropertyRuleMap.get(className));
    }
    transformNode(document, node, dataObjectClass, classPropertyRuleMap.get("*"));
}

From source file:org.kuali.rice.krad.devtools.maintainablexml.MaintainableXMLConversionServiceImpl.java

private void transformNode(Document document, Node node, Class<?> currentClass,
        Map<String, String> propertyMappings) throws ClassNotFoundException, XPathExpressionException,
        IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException {
    for (Node childNode = node.getFirstChild(); childNode != null;) {
        Node nextChild = childNode.getNextSibling();
        String propertyName = childNode.getNodeName();
        if (childNode.hasAttributes()) {
            XPath xpath = XPathFactory.newInstance().newXPath();
            Node serializationAttribute = childNode.getAttributes().getNamedItem(SERIALIZATION_ATTRIBUTE);
            if (serializationAttribute != null
                    && StringUtils.equals(serializationAttribute.getNodeValue(), "custom")) {
                Node classAttribute = childNode.getAttributes().getNamedItem(CLASS_ATTRIBUTE);
                if (classAttribute != null && StringUtils.equals(classAttribute.getNodeValue(),
                        "org.kuali.rice.kns.util.TypedArrayList")) {
                    ((Element) childNode).removeAttribute(SERIALIZATION_ATTRIBUTE);
                    ((Element) childNode).removeAttribute(CLASS_ATTRIBUTE);
                    XPathExpression listSizeExpression = xpath.compile("//" + propertyName
                            + "/org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl/default/size/text()");
                    String size = (String) listSizeExpression.evaluate(childNode, XPathConstants.STRING);
                    List<Node> nodesToAdd = new ArrayList<Node>();
                    if (StringUtils.isNotBlank(size) && Integer.valueOf(size) > 0) {
                        XPathExpression listTypeExpression = xpath.compile("//" + propertyName
                                + "/org.kuali.rice.kns.util.TypedArrayList/default/listObjectType/text()");
                        String listType = (String) listTypeExpression.evaluate(childNode,
                                XPathConstants.STRING);
                        XPathExpression listContentsExpression = xpath.compile("//" + propertyName
                                + "/org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl/" + listType);
                        NodeList listContents = (NodeList) listContentsExpression.evaluate(childNode,
                                XPathConstants.NODESET);
                        for (int i = 0; i < listContents.getLength(); i++) {
                            Node tempNode = listContents.item(i);
                            transformClassNode(document, tempNode);
                            nodesToAdd.add(tempNode);
                        }//from  ww w . jav  a2  s. c o m
                    }
                    for (Node removeNode = childNode.getFirstChild(); removeNode != null;) {
                        Node nextRemoveNode = removeNode.getNextSibling();
                        childNode.removeChild(removeNode);
                        removeNode = nextRemoveNode;
                    }
                    for (Node nodeToAdd : nodesToAdd) {
                        childNode.appendChild(nodeToAdd);
                    }
                } else {
                    ((Element) childNode).removeAttribute(SERIALIZATION_ATTRIBUTE);

                    XPathExpression mapContentsExpression = xpath.compile("//" + propertyName + "/map/string");
                    NodeList mapContents = (NodeList) mapContentsExpression.evaluate(childNode,
                            XPathConstants.NODESET);
                    List<Node> nodesToAdd = new ArrayList<Node>();
                    if (mapContents.getLength() > 0 && mapContents.getLength() % 2 == 0) {
                        for (int i = 0; i < mapContents.getLength(); i++) {
                            Node keyNode = mapContents.item(i);
                            Node valueNode = mapContents.item(++i);
                            Node entryNode = document.createElement("entry");
                            entryNode.appendChild(keyNode);
                            entryNode.appendChild(valueNode);
                            nodesToAdd.add(entryNode);
                        }
                    }
                    for (Node removeNode = childNode.getFirstChild(); removeNode != null;) {
                        Node nextRemoveNode = removeNode.getNextSibling();
                        childNode.removeChild(removeNode);
                        removeNode = nextRemoveNode;
                    }
                    for (Node nodeToAdd : nodesToAdd) {
                        childNode.appendChild(nodeToAdd);
                    }
                }
            }
        }
        if (propertyMappings != null && propertyMappings.containsKey(propertyName)) {
            String newPropertyName = propertyMappings.get(propertyName);
            if (StringUtils.isNotBlank(newPropertyName)) {
                document.renameNode(childNode, null, newPropertyName);
                propertyName = newPropertyName;
            } else {
                // If there is no replacement name then the element needs
                // to be removed and skip all other processing
                node.removeChild(childNode);
                childNode = nextChild;
                continue;
            }
        }

        if (dateRuleMap != null && dateRuleMap.containsKey(propertyName)) {
            String newDateValue = dateRuleMap.get(propertyName);
            if (StringUtils.isNotBlank(newDateValue)) {
                if (childNode.getTextContent().length() == 10) {
                    childNode.setTextContent(childNode.getTextContent() + " " + newDateValue);

                }
            }
        }

        if (currentClass != null) {
            if (childNode.hasChildNodes() && !(Collection.class.isAssignableFrom(currentClass)
                    || Map.class.isAssignableFrom(currentClass))) {
                Class<?> propertyClass = PropertyUtils.getPropertyType(currentClass.newInstance(),
                        propertyName);
                if (propertyClass != null && classPropertyRuleMap.containsKey(propertyClass.getName())) {
                    transformNode(document, childNode, propertyClass,
                            this.classPropertyRuleMap.get(propertyClass.getName()));
                }
                transformNode(document, childNode, propertyClass, classPropertyRuleMap.get("*"));
            }
        }
        childNode = nextChild;
    }
}

From source file:org.kuali.rice.krad.service.impl.MaintainableXMLConversionServiceImpl.java

private void transformNode(Document document, Node node, Class<?> currentClass,
        Map<String, String> propertyMappings) throws ClassNotFoundException, XPathExpressionException,
        IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException {
    for (Node childNode = node.getFirstChild(); childNode != null;) {
        Node nextChild = childNode.getNextSibling();
        String propertyName = childNode.getNodeName();
        if (childNode.hasAttributes()) {
            XPath xpath = XPathFactory.newInstance().newXPath();
            Node serializationAttribute = childNode.getAttributes().getNamedItem(SERIALIZATION_ATTRIBUTE);
            if (serializationAttribute != null
                    && StringUtils.equals(serializationAttribute.getNodeValue(), "custom")) {
                Node classAttribute = childNode.getAttributes().getNamedItem(CLASS_ATTRIBUTE);
                if (classAttribute != null && StringUtils.equals(classAttribute.getNodeValue(),
                        "org.kuali.rice.kns.util.TypedArrayList")) {
                    ((Element) childNode).removeAttribute(SERIALIZATION_ATTRIBUTE);
                    ((Element) childNode).removeAttribute(CLASS_ATTRIBUTE);
                    XPathExpression listSizeExpression = xpath.compile("//" + propertyName
                            + "/org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl/default/size/text()");
                    String size = (String) listSizeExpression.evaluate(childNode, XPathConstants.STRING);
                    List<Node> nodesToAdd = new ArrayList<Node>();
                    if (StringUtils.isNotBlank(size) && Integer.valueOf(size) > 0) {
                        XPathExpression listTypeExpression = xpath.compile("//" + propertyName
                                + "/org.kuali.rice.kns.util.TypedArrayList/default/listObjectType/text()");
                        String listType = (String) listTypeExpression.evaluate(childNode,
                                XPathConstants.STRING);
                        XPathExpression listContentsExpression = xpath.compile("//" + propertyName
                                + "/org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl/" + listType);
                        NodeList listContents = (NodeList) listContentsExpression.evaluate(childNode,
                                XPathConstants.NODESET);
                        for (int i = 0; i < listContents.getLength(); i++) {
                            Node tempNode = listContents.item(i);
                            transformClassNode(document, tempNode);
                            nodesToAdd.add(tempNode);
                        }//  w  w w . j  a  v a2  s . c  o  m
                    }
                    for (Node removeNode = childNode.getFirstChild(); removeNode != null;) {
                        Node nextRemoveNode = removeNode.getNextSibling();
                        childNode.removeChild(removeNode);
                        removeNode = nextRemoveNode;
                    }
                    for (Node nodeToAdd : nodesToAdd) {
                        childNode.appendChild(nodeToAdd);
                    }
                } else {
                    ((Element) childNode).removeAttribute(SERIALIZATION_ATTRIBUTE);

                    XPathExpression mapContentsExpression = xpath.compile("//" + propertyName + "/map/string");
                    NodeList mapContents = (NodeList) mapContentsExpression.evaluate(childNode,
                            XPathConstants.NODESET);
                    List<Node> nodesToAdd = new ArrayList<Node>();
                    if (mapContents.getLength() > 0 && mapContents.getLength() % 2 == 0) {
                        for (int i = 0; i < mapContents.getLength(); i++) {
                            Node keyNode = mapContents.item(i);
                            Node valueNode = mapContents.item(++i);
                            Node entryNode = document.createElement("entry");
                            entryNode.appendChild(keyNode);
                            entryNode.appendChild(valueNode);
                            nodesToAdd.add(entryNode);
                        }
                    }
                    for (Node removeNode = childNode.getFirstChild(); removeNode != null;) {
                        Node nextRemoveNode = removeNode.getNextSibling();
                        childNode.removeChild(removeNode);
                        removeNode = nextRemoveNode;
                    }
                    for (Node nodeToAdd : nodesToAdd) {
                        childNode.appendChild(nodeToAdd);
                    }
                }
            }
        }
        if (propertyMappings != null && propertyMappings.containsKey(propertyName)) {
            String newPropertyName = propertyMappings.get(propertyName);
            if (StringUtils.isNotBlank(newPropertyName)) {
                document.renameNode(childNode, null, newPropertyName);
                propertyName = newPropertyName;
            } else {
                // If there is no replacement name then the element needs
                // to be removed and skip all other processing
                node.removeChild(childNode);
                childNode = nextChild;
                continue;
            }
        }
        if (childNode.hasChildNodes() && !(Collection.class.isAssignableFrom(currentClass)
                || Map.class.isAssignableFrom(currentClass))) {
            if (propertyName.equals("principalId") && (node.getNodeName().equals("dataManagerUser")
                    || node.getNodeName().equals("dataStewardUser"))) {
                currentClass = new org.kuali.rice.kim.impl.identity.PersonImpl().getClass();
            }
            Class<?> propertyClass = PropertyUtils.getPropertyType(currentClass.newInstance(), propertyName);
            if (propertyClass != null && classPropertyRuleMap.containsKey(propertyClass.getName())) {
                transformNode(document, childNode, propertyClass,
                        this.classPropertyRuleMap.get(propertyClass.getName()));
            }
            transformNode(document, childNode, propertyClass, classPropertyRuleMap.get("*"));
        }
        childNode = nextChild;
    }
}

From source file:org.ojbc.bundles.adapters.staticmock.StaticMockQuery.java

private Document createFirearmRegistrationDocument(Document document, String firearmId) throws Exception {
    Document copy = createNewDocument();
    copy.appendChild(copy.importNode(document.getDocumentElement(), true));
    Node rootElement = XmlUtils.xPathNodeSearch(copy, "/*");
    LOG.debug("Keeper: " + firearmId);
    NodeList otherFirearmNodes = XmlUtils.xPathNodeListSearch(rootElement,
            "firearm-ext:Firearm[@s:id != '" + firearmId + "']");
    for (int i = 0; i < otherFirearmNodes.getLength(); i++) {
        Node goner = otherFirearmNodes.item(i);
        LOG.debug("Goner: " + XmlUtils.xPathStringSearch(goner, "@s:id"));
        rootElement.removeChild(goner);//  w  w  w.ja  va  2s .co m
    }
    NodeList otherItemRegNodes = XmlUtils.xPathNodeListSearch(rootElement,
            "firearm-ext:ItemRegistration[@s:id != /firearm-doc:PersonFirearmRegistrationQueryResults/nc:PropertyRegistrationAssociation[nc:ItemReference/@s:ref='"
                    + firearmId + "']/nc:ItemRegistrationReference/@s:ref]");
    for (int i = 0; i < otherItemRegNodes.getLength(); i++) {
        rootElement.removeChild(otherItemRegNodes.item(i));
    }
    NodeList otherRegAssociationNodes = XmlUtils.xPathNodeListSearch(rootElement,
            "nc:PropertyRegistrationAssociation[nc:ItemReference/@s:ref != '" + firearmId + "']");
    for (int i = 0; i < otherRegAssociationNodes.getLength(); i++) {
        rootElement.removeChild(otherRegAssociationNodes.item(i));
    }
    copy.renameNode(rootElement, rootElement.getNamespaceURI(), "FirearmRegistrationQueryResults");
    Node documentRootElement = XmlUtils.xPathNodeSearch(document, "/*");
    rootElement.setPrefix(documentRootElement.getPrefix());
    return copy;
}

From source file:org.ojbc.util.xml.TestXmlUtils.java

@Test
public void testCompare() throws Exception {
    Document d = db.newDocument();
    Element e1 = d.createElementNS(OjbcNamespaceContext.NS_PERSON_SEARCH_RESULTS_EXT, "e1");
    d.appendChild(e1);/*  w  w  w .  j  a  v a2 s  .  c o m*/
    Element e2 = d.createElementNS(OjbcNamespaceContext.NS_PERSON_SEARCH_RESULTS_EXT, "e2");
    e1.appendChild(e2);
    Element e = d.createElementNS(OjbcNamespaceContext.NS_PERSON_SEARCH_RESULTS_EXT, "e11");
    e1.appendChild(e);
    e.setTextContent("Text");
    Document d2 = db.newDocument();
    e1 = d2.createElementNS(OjbcNamespaceContext.NS_PERSON_SEARCH_RESULTS_EXT, "e1");
    d2.appendChild(e1);
    e2 = d2.createElementNS(OjbcNamespaceContext.NS_PERSON_SEARCH_RESULTS_EXT, "e2");
    e1.appendChild(e2);
    e = d2.createElementNS(OjbcNamespaceContext.NS_PERSON_SEARCH_RESULTS_EXT, "e11");
    e1.appendChild(e);
    e.setTextContent("Text");
    assertTrue(XmlUtils.compare(d.getDocumentElement(), d2.getDocumentElement()));
    e.setTextContent("New Text");
    assertFalse(XmlUtils.compare(d.getDocumentElement(), d2.getDocumentElement()));
    e.setTextContent("Text");
    assertTrue(XmlUtils.compare(d.getDocumentElement(), d2.getDocumentElement()));
    d2.renameNode(e, OjbcNamespaceContext.NS_PERSON_SEARCH_RESULTS_EXT, "newname");
    assertFalse(XmlUtils.compare(d.getDocumentElement(), d2.getDocumentElement()));
    d2.renameNode(e, OjbcNamespaceContext.NS_PERSON_SEARCH_RESULTS_EXT, "e11");
    assertTrue(XmlUtils.compare(d.getDocumentElement(), d2.getDocumentElement()));
    e = d2.createElementNS(OjbcNamespaceContext.NS_PERSON_SEARCH_RESULTS_EXT, "e12");
    e1.appendChild(e);
    assertFalse(XmlUtils.compare(d.getDocumentElement(), d2.getDocumentElement()));

}

From source file:org.openestate.io.core.XmlUtils.java

/**
 * Replace the namespace of a {@link Node} and its children.
 *
 * @param doc//  w w w .  ja  v  a2s.  co  m
 * the document to update
 *
 * @param node
 * the node to update
 *
 * @param newNamespaceURI
 * the new namespace URI
 */
public static void replaceNamespace(Document doc, Node node, String newNamespaceURI) {
    if (node instanceof Attr) {
        doc.renameNode(node, newNamespaceURI, node.getLocalName());
    } else if (node instanceof Element) {
        doc.renameNode(node, newNamespaceURI, node.getLocalName());
        NodeList children = node.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            XmlUtils.replaceNamespace(doc, children.item(i), newNamespaceURI);
        }
    }
}

From source file:org.openmrs.module.metadatasharing.converter.BaseConverter.java

protected Element newElement(Document doc, String name, Object object, ConverterContext context)
        throws SerializationException {
    String serializedObject = MetadataSharing.getInstance().getMetadataSerializer().serialize(object);

    Document tmpDoc;
    try {/*  www  .  java 2 s  . c o m*/
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        tmpDoc = db.parse(new InputSource(new StringReader(serializedObject)));
    } catch (Exception e) {
        throw new SerializationException(e);
    }

    Element element = tmpDoc.getDocumentElement();
    element = (Element) tmpDoc.renameNode(element, "", name);

    element = (Element) newReference(element, context);
    newChildReferences(element, context);

    Element importedElement = (Element) doc.importNode(element, true);

    return importedElement;
}

From source file:org.openmrs.module.metadatasharing.converter.ConceptMap19Converter.java

@Override
public void convert(Document doc, Version fromVersion, Version toVersion, ConverterContext context)
        throws SerializationException {
    if (fromVersion.compareTo(new Version("1.9")) >= 0 || toVersion.compareTo(new Version("1.9")) < 0) {
        return;//from w  ww. ja  v  a 2  s . c  om
    }

    Map<String, Element> mapTypeElements = new HashMap<String, Element>();

    NodeList maps = doc.getElementsByTagName("org.openmrs.ConceptMap");
    for (int i = 0; i < maps.getLength(); i++) {
        Node map = maps.item(i);

        Element commentElement = getChildElement(map, "comment");
        if (commentElement == null) {
            continue;
        }

        map.removeChild(commentElement);

        String mapTypeName = getMapTypeName(commentElement);

        if (mapTypeName == null) {
            continue;
        }

        Element mapTypeElement = mapTypeElements.get(mapTypeName);

        if (mapTypeElement == null) {
            ConceptMapType mapType = Context.getConceptService().getConceptMapTypeByName(mapTypeName);

            if (mapType == null) {
                continue;
            }

            mapTypeElement = newElement(doc, "conceptMapType", mapType, context);
            mapTypeElements.put(mapTypeName, mapTypeElement);

            map.appendChild(mapTypeElement);
        } else {
            Element reference = doc.createElement("conceptMapTye");
            newReferenced(reference, mapTypeElement);
            map.appendChild(reference);
        }
    }

    Map<String, Element> referenceTermElements = new HashMap<String, Element>();

    for (int i = 0; i < maps.getLength(); i++) {
        Node map = maps.item(i);
        Element source = getChildElement(map, "source");
        map.removeChild(source);
        Element referencedSource = (Element) reference(source, context);

        Element sourceCode = getChildElement(map, "sourceCode");
        map.removeChild(sourceCode);

        //ConceptReferenceTerms are the same if source and sourceCode are the same
        String key = referencedSource.getAttribute("uuid") + sourceCode.getTextContent();

        Element referenceTermElement = referenceTermElements.get(key);

        if (referenceTermElement == null) {
            ConceptReferenceTerm referenceTerm = new ConceptReferenceTerm();
            String uuid = UUID.nameUUIDFromBytes(((Element) map).getAttribute("uuid").getBytes()).toString();
            referenceTerm.setUuid(uuid);
            referenceTerm.setCode(sourceCode.getTextContent());
            referenceTermElement = newElement(doc, "conceptReferenceTerm", referenceTerm, context);
            source = (Element) source.cloneNode(true);
            source = (Element) doc.renameNode(source, "", "conceptSource");
            referenceTermElement.appendChild(source);

            referenceTermElements.put(key, referenceTermElement);
            map.appendChild(referenceTermElement);
        } else {
            Element reference = doc.createElement("conceptReferenceTerm");
            newReferenced(reference, referenceTermElement);
            map.appendChild(reference);
        }
    }
}

From source file:org.openmrs.module.metadatasharing.converter.ConceptMapConverter.java

/**
 * @see org.openmrs.module.metadatasharing.converter.BaseConverter#convert(org.w3c.dom.Document, org.openmrs.module.metadatasharing.util.Version, org.openmrs.module.metadatasharing.util.Version, org.openmrs.module.metadatasharing.converter.BaseConverter.ConverterContext)
 * @should replace source if the from version is pre one nine
 * @should replace nothing if the to version is post one nine
 *//* w  w w .jav  a  2s . co m*/
@Override
public void convert(Document doc, Version fromVersion, Version toVersion, ConverterContext context)
        throws SerializationException {
    if (fromVersion.compareTo(new Version("1.9")) >= 0 || toVersion.compareTo(new Version("1.9")) < 0) {
        return;
    }

    Map<String, Element> mapTypeElements = new HashMap<String, Element>();

    NodeList maps = doc.getElementsByTagName("org.openmrs.ConceptMap");
    for (int i = 0; i < maps.getLength(); i++) {
        Node map = maps.item(i);

        Element commentElement = getChildElement(map, "comment");
        if (commentElement == null) {
            continue;
        }

        map.removeChild(commentElement);

        String mapTypeName = getMapTypeName(commentElement);

        if (mapTypeName == null) {
            continue;
        }

        Element mapTypeElement = mapTypeElements.get(mapTypeName);

        if (mapTypeElement == null) {
            ConceptMapType mapType = Context.getConceptService().getConceptMapTypeByName(mapTypeName);

            if (mapType == null) {
                continue;
            }

            mapTypeElement = newElement(doc, "conceptMapType", mapType, context);
            mapTypeElements.put(mapTypeName, mapTypeElement);

            map.appendChild(mapTypeElement);
        } else {
            Element reference = doc.createElement("conceptMapTye");
            newReferenced(reference, mapTypeElement);
            map.appendChild(reference);
        }
    }

    Map<String, Element> referenceTermElements = new HashMap<String, Element>();

    for (int i = 0; i < maps.getLength(); i++) {
        Node map = maps.item(i);
        Element source = getChildElement(map, "source");
        map.removeChild(source);
        Element referencedSource = (Element) reference(source, context);

        Element sourceCode = getChildElement(map, "sourceCode");
        map.removeChild(sourceCode);

        //ConceptReferenceTerms are the same if source and sourceCode are the same
        String key = referencedSource.getAttribute("uuid") + sourceCode.getTextContent();

        Element referenceTermElement = referenceTermElements.get(key);

        if (referenceTermElement == null) {
            ConceptReferenceTerm referenceTerm = new ConceptReferenceTerm();
            String uuid = UUID.nameUUIDFromBytes(((Element) map).getAttribute("uuid").getBytes()).toString();
            referenceTerm.setUuid(uuid);
            referenceTerm.setCode(sourceCode.getTextContent());
            referenceTermElement = newElement(doc, "conceptReferenceTerm", referenceTerm, context);
            source = (Element) source.cloneNode(true);
            source = (Element) doc.renameNode(source, "", "conceptSource");
            referenceTermElement.appendChild(source);

            referenceTermElements.put(key, referenceTermElement);
            map.appendChild(referenceTermElement);
        } else {
            Element reference = doc.createElement("conceptReferenceTerm");
            newReferenced(reference, referenceTermElement);
            map.appendChild(reference);
        }
    }
}

From source file:org.openmrs.projectbuendia.webservices.rest.XformResource.java

/**
 * Converts a vanilla Xform into one that ODK Collect is happy to work with.
 * This requires://from w  w w. j a v  a 2  s  . c  o  m
 * <ul>
 * <li>Changing the namespace of the the root element to http://www.w3.org/1999/xhtml
 * <li>Wrapping the model element in an HTML head element, with a title child element
 * <li>Wrapping remaining elements in an HTML body element
 * </ul>
 */
static String convertToOdkCollect(String xml, String title) throws IOException, SAXException {
    // Change the namespace of the root element. I haven't figured out a way
    // to do
    // this within a document; removing the root element from the document
    // seems
    // to do odd things... so instead, we import it into a new document.
    Document oldDoc = XmlUtil.parse(xml);
    Document doc = XmlUtil.getDocumentBuilder().newDocument();
    Element root = (Element) doc.importNode(oldDoc.getDocumentElement(), true);
    root = (Element) doc.renameNode(root, HTML_NAMESPACE, "h:form");
    doc.appendChild(root);

    // Prepare the new wrapper elements
    Element head = doc.createElementNS(HTML_NAMESPACE, "h:head");
    Element titleElement = XmlUtil.appendElementNS(head, HTML_NAMESPACE, "h:title");
    titleElement.setTextContent(title);
    Element body = doc.createElementNS(HTML_NAMESPACE, "h:body");

    // Find the model element to go in the head, and all its following
    // siblings to go in the body.
    // We do this before moving any elements, for the sake of sanity.
    Element model = getElementOrThrowNS(root, XFORMS_NAMESPACE, "model");
    List<Node> nodesAfterModel = new ArrayList<>();
    Node nextSibling = model.getNextSibling();
    while (nextSibling != null) {
        nodesAfterModel.add(nextSibling);
        nextSibling = nextSibling.getNextSibling();
    }

    // Now we're done with the preparation, we can move everything.
    head.appendChild(model);
    for (Node node : nodesAfterModel) {
        body.appendChild(node);
    }

    // Having removed the model and everything after it, we can now just
    // append the head and body to the document element...
    root.appendChild(head);
    root.appendChild(body);

    return XformsUtil.doc2String(doc);
}