void (Node node, Document doc, Element current, boolean atRoot) { // Recurse through the tree switch (node.getNodeType()) { case Node.DOCUMENT_NODE: NodeList nodes = node.getChildNodes(); for (int i = 0, size = nodes.getLength(); i < size; i++) { buildTree(nodes.item(i), doc, current, true); } break; case Node.ELEMENT_NODE: String nodeName = node.getNodeName(); String prefix = NS_PREFIX_DEFAULT; String localName = nodeName; int colon = nodeName.indexOf(':'); if (colon >= 0) { prefix = nodeName.substring(0, colon); localName = nodeName.substring(colon + 1); } // Get element's namespace Namespace ns; String uri = node.getNamespaceURI(); if (uri == null) { ns = (current == null) ? Namespace.NO_NAMESPACE : current.getNamespace(prefix); } else { ns = Namespace.getNamespace(prefix, uri); } Element element = factory.element(localName, ns); if (atRoot) { // If at root, set as document root factory.setRoot(doc, element); } else { // else add to a parent element factory.addContent(current, element); } // Add namespaces NamedNodeMap attributeList = node.getAttributes(); int attsize = attributeList.getLength(); for (int i = 0; i < attsize; i++) { Attr att = (Attr)attributeList.item(i); String attname = att.getName(); if (attname.startsWith(NS_PREFIX_XMLNS)) { String attPrefix = NS_PREFIX_DEFAULT; colon = attname.indexOf(':'); if (colon >= 0) { attPrefix = attname.substring(colon + 1); } String attvalue = att.getValue(); Namespace declaredNS = Namespace.getNamespace(attPrefix, attvalue); // Add as additional namespaces if it's different // to this element's namespace (perhaps we should // also have logic not to mark them as additional if // it's been done already, but it probably doesn't // matter) if (prefix.equals(attPrefix)) { // RL: note, it should also be true that uri.equals(attvalue) // if not, then the parser is boken. // further, declaredNS should be exactly the same as ns // so the following should, in fact do nothing. element.setNamespace(declaredNS); } else { factory.addNamespaceDeclaration(element, declaredNS); } } } // Add attributes for (int i = 0; i < attsize; i++) { Attr att = (Attr)attributeList.item(i); String attname = att.getName(); if (!attname.startsWith(NS_PREFIX_XMLNS)) { String attPrefix = NS_PREFIX_DEFAULT; String attLocalName = attname; colon = attname.indexOf(':'); if (colon >= 0) { attPrefix = attname.substring(0, colon); attLocalName = attname.substring(colon + 1); } String attvalue = att.getValue(); // Get attribute's namespace Namespace attNS = null; String attURI = att.getNamespaceURI(); if (attPrefix.isEmpty() && (attURI == null || NS_URI_DEFAULT.equals(attURI))) { attNS = Namespace.NO_NAMESPACE; } else { // various conditions can lead here. // the logical one is that we have a prefix for the // attribute, and also a namespace URI. // The alternative to that is in some conditions, // the parser could have a 'default' or 'fixed' // attribute that comes from an XSD used for // validation. In that case, there may not be a prefix // There's also the possibility the DOM contains // garbage. if (attPrefix.length() > 0) { // If the att has a prefix, we can assume that // the DOM is valid, and we can just use the prefix. // if this prefix conflicts with some other namespace // then we re-declare it. If redeclaring it screws up // other attributes in this Element, then the DOM // was broken to start with. if (attURI == null) { // this can happen when the DOM is created // without being namespace aware. we have a // prefix, but the URI is not embedded in // the Attribute itself. It must be declared // on the element somewhere.... // https://github.com/hunterhacker/jdom/issues/138 attNS = element.getNamespace(attPrefix); } else { attNS = Namespace.getNamespace(attPrefix, attURI); } } else { // OK, no prefix. // must be a defaulted value from an XSD. // perhaps we can find the namespace in our // element's ancestry, and use the prefix from that. HashMap<String, Namespace> tmpmap = new HashMap<>(); for (Namespace nss : element.getNamespacesInScope()) { if (nss.getPrefix().length() > 0 && nss.getURI().equals(attURI)) { attNS = nss; break; } tmpmap.put(nss.getPrefix(), nss); } if (attNS == null) { // we cannot find a 'prevailing' namespace that has a prefix // that is for this namespace. // This basically means that there's an XMLSchema, for the // DEFAULT namespace, and there's a defaulted/fixed // attribute definition in the XMLSchema that's targeted // for this namespace,... but, the user has either not // declared a prefixed version of the namespace, or has // re-declared the same prefix at a lower level with a // different namespace. // All of these things are possible. // Create some sort of default prefix. int cnt = 0; String base = "attns"; String pfx = base + cnt; while (tmpmap.containsKey(pfx)) { cnt++; pfx = base + cnt; } attNS = Namespace.getNamespace(pfx, attURI); } } } Attribute attribute = factory.attribute(attLocalName, attvalue, attNS); factory.setAttribute(element, attribute); } } // Recurse on child nodes // The list should never be null nor should it ever contain // null nodes, but some DOM impls are broken NodeList children = node.getChildNodes(); int size = children.getLength(); for (int i = 0; i < size; i++) { Node item = children.item(i); if (item != null) { buildTree(item, doc, element, false); } } break; case Node.TEXT_NODE: factory.addContent(current, build((Text)node)); break; case Node.CDATA_SECTION_NODE: factory.addContent(current, build((CDATASection)node)); break; case Node.PROCESSING_INSTRUCTION_NODE: case Node.COMMENT_NODE: break; case Node.ENTITY_REFERENCE_NODE: factory.addContent(current, build((EntityReference)node)); break; case Node.ENTITY_NODE: // ?? break; case Node.DOCUMENT_TYPE_NODE: factory.addContent(doc, build((DocumentType)node)); break; } }