Java + DOM: Comment définir l’espace de base d’un document (déjà créé)?

Je traite avec un object Document déjà créé . Je dois être en mesure de définir son espace de noms de base (nom d’atsortingbut “xmlns”) à une certaine valeur. Mon entrée est DOM et est quelque chose comme:

...some content... 

Ce dont j’ai besoin, c’est DOM qui ressemble à quelque chose comme:

 ...some content... 

C’est tout. Facile, n’est-ce pas? Faux! Pas avec DOM!

J’ai essayé ce qui suit:

1) Utilisation de doc.getDocumentElement (). SetAtsortingbute (“xmlns”, “myNamespace”)

Je reçois un document avec xmlns vide (cela fonctionne avec n’importe quel autre nom d’atsortingbut!)

 ... 

2) Utilisation de renameNode (…)

Clonez d’ abord le document:

 Document input = /*that external Document whose namespace I want to alter*/; DocumentBuilderFactory BUILDER_FACTORY_NS = DocumentBuilderFactory.newInstance(); BUILDER_FACTORY_NS.setNamespaceAware(true); Document output = BUILDER_NS.newDocument(); output.appendChild(output.importNode(input.getDocumentElement(), true)); 

Il manque vraiment document.clone (), mais c’est peut-être juste moi.

Renommez maintenant le noeud racine :

 output.renameNode(output.getDocumentElement(),"myNamespace", output.getDocumentElement().getTagName()); 

Maintenant, n’est-ce pas simple? 😉

Ce que je reçois maintenant est:

     

Donc (comme nous nous y attendions tous, non?) , Cela renomme l’espace de noms uniquement du nœud racine .

Je vous maudis, DOM!

Est-il possible de le faire récursivement (sans écrire une méthode récursive propre)?

S’il vous plaît aider;)

S’il vous plaît, ne me conseillez pas de contourner ce problème, par exemple en transformant DOM en autre chose, en modifiant l’espace de noms et en le transformant. J’ai besoin de DOM parce que c’est le moyen standard le plus rapide de manipuler XML.

Remarque: j’utilise le dernier JDK.

MODIFIER
Suppression des mauvaises hypothèses de la question concernant le préfixe d’ espace de nom.

J’ai eu le même problème aujourd’hui. J’ai fini par utiliser des parties de la réponse de @ivan_ivanovich_ivanoff mais j’ai supprimé la récursivité et corrigé quelques bugs.

Très important: si l’ancien espace de nommage est null vous devez append deux traductions, une de null à votre nouvel namespaceURI et une autre de "" à votre nouvel namespaceURI . Cela se produit car le premier appel à renameNode changera les noeuds existants qui ont un namespaceURI null en xmlns="" .

Exemple d’utilisation:

 Document xmlDoc = ...; new XmlNamespaceTranslator() .addTranslation(null, "new_ns") .addTranslation("", "new_ns") .translateNamespaces(xmlDoc); // xmlDoc will have nodes with namespace null or "" changed to "new_ns" 

Le code source complet suit:

 public class XmlNamespaceTranslator { private Map, Value> translations = new HashMap, Value>(); public XmlNamespaceTranslator addTranslation(Ssortingng fromNamespaceURI, Ssortingng toNamespaceURI) { Key key = new Key(fromNamespaceURI); Value value = new Value(toNamespaceURI); this.translations.put(key, value); return this; } public void translateNamespaces(Document xmlDoc) { Stack nodes = new Stack(); nodes.push(xmlDoc.getDocumentElement()); while (!nodes.isEmpty()) { Node node = nodes.pop(); switch (node.getNodeType()) { case Node.ATTRIBUTE_NODE: case Node.ELEMENT_NODE: Value value = this.translations.get(new Key(node.getNamespaceURI())); if (value != null) { // the reassignment to node is very important. as per javadoc renameNode will // try to modify node (first parameter) in place. If that is not possible it // will replace that node for a new created one and return it to the caller. // if we did not reassign node we will get no childs in the loop below. node = xmlDoc.renameNode(node, value.getValue(), node.getNodeName()); } break; } // for atsortingbutes of this node NamedNodeMap atsortingbutes = node.getAtsortingbutes(); if (!(atsortingbutes == null || atsortingbutes.getLength() == 0)) { for (int i = 0, count = atsortingbutes.getLength(); i < count; ++i) { Node attribute = attributes.item(i); if (attribute != null) { nodes.push(attribute); } } } // for child nodes of this node NodeList childNodes = node.getChildNodes(); if (!(childNodes == null || childNodes.getLength() == 0)) { for (int i = 0, count = childNodes.getLength(); i < count; ++i) { Node childNode = childNodes.item(i); if (childNode != null) { nodes.push(childNode); } } } } } // these will allow null values to be stored on a map so that we can distinguish // from values being on the map or not. map implementation returns null if the there // is no map element with a given key. If the value is null there is no way to // distinguish from value not being on the map or value being null. these classes // remove ambiguity. private static class Holder { protected final T value; public Holder(T value) { this.value = value; } public T getValue() { return value; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Holder other = (Holder) obj; if (value == null) { if (other.value != null) return false; } else if (!value.equals(other.value)) return false; return true; } } private static class Key extends Holder { public Key(T value) { super(value); } } private static class Value extends Holder { public Value(T value) { super(value); } } } 

En plus de définir le préfixe, vous devez également déclarer votre espace de noms quelque part.

[EDIT] Si vous examinez le paquet org.w3c.dom , vous remarquerez qu’il n’y a aucun support pour les espaces de noms, sauf que vous pouvez créer un noeud Document avec un URI d’espace de noms:

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); DOMImplementation DOMImplementation = builder.getDOMImplementation(); Document doc = DOMImplementation.createDocument( "http://www.somecompany.com/2005/xyz", // namespace "root", null /*DocumentType*/); Element root = doc.getDocumentElement(); root.setPrefix("xyz"); root.setAtsortingbute( "xmlns:xyz", "http://www.somecompany.com/2005/xyz"); 

Avec l’API DOM standard W3C de Java 5 (et supérieur), il n’est pas possible de modifier l’espace de nommage d’un noeud.

Mais l’API DOM W3C n’est que quelques interfaces. Vous devez donc essayer d’examiner l’implémentation (c’est-à-dire la classe réelle de votre instance de document) et de la convertir en type réel. Ce type devrait avoir des méthodes supplémentaires et si vous avez de la chance, vous pouvez les utiliser pour modifier l’espace de noms.

Eh bien, voici la “solution” récursive:
(J’espère toujours que quelqu’un pourrait trouver une meilleure façon de le faire)

 public static void renameNamespaceRecursive(Document doc, Node node, Ssortingng namespace) { if (node.getNodeType() == Node.ELEMENT_NODE) { System.out.println("renaming type: " + node.getClass() + ", name: " + node.getNodeName()); doc.renameNode(node, namespace, node.getNodeName()); } NodeList list = node.getChildNodes(); for (int i = 0; i < list.getLength(); ++i) { renameNamespaceRecursive(doc, list.item(i), namespace); } } 

Semble fonctionner, même si je ne sais pas s'il est correct de renommer uniquement le type de noeud ELEMENT_NODE ou si d'autres types de noeud doivent être renommés.

nous pouvons changer l’espace de noms xml en utilisant l’parsingur sax, essayez ceci

 import java.util.ListIterator; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Namespace; import org.dom4j.QName; import org.dom4j.Visitor; import org.dom4j.VisitorSupport; import org.dom4j.io.SAXReader; public class VisitorExample { public static void main(Ssortingng[] args) throws Exception { Document doc = new SAXReader().read("test.xml"); Namespace oldNs = Namespace.get("oldNamespace"); Namespace newNs = Namespace.get("newPrefix", "newNamespace"); Visitor visitor = new NamespaceChangingVisitor(oldNs, newNs); doc.accept(visitor); System.out.println(doc.asXML()); } } class NamespaceChangingVisitor extends VisitorSupport { private Namespace from; private Namespace to; public NamespaceChangingVisitor(Namespace from, Namespace to) { this.from = from; this.to = to; } public void visit(Element node) { Namespace ns = node.getNamespace(); if (ns.getURI().equals(from.getURI())) { QName newQName = new QName(node.getName(), to); node.setQName(newQName); } ListIterator namespaces = node.additionalNamespaces().listIterator(); while (namespaces.hasNext()) { Namespace additionalNamespace = (Namespace) namespaces.next(); if (additionalNamespace.getURI().equals(from.getURI())) { namespaces.remove(); } } } } 

Une légère variation du post d’origine d’Ivan a fonctionné pour moi: définir l’atsortingbut sur le nœud du document.

 xslRoot.setAtsortingbute("xmlns:fo", "http://www.w3.org/1999/XSL/Format"); 

  • xslRoot est le document / élément racine / noeud,
  • fo est l’identifiant de l’espace de nommage

J’espère que ça aide quelqu’un!

Mike Watts

Si vous êtes d’accord avec l’utilisation des classes Xerces, vous pouvez créer un DOMParser qui remplace l’URI des atsortingbuts et des éléments par vos URI corrigés:

 import org.apache.xerces.parsers.DOMParser; public static class MyDOMParser extends DOMParser { private Map fixupMap = ...; @Override protected Attr createAttrNode(QName attrQName) { if (fixupMap.containsKey(attrQName.uri)) attrQName.uri = fixupMap.get(attrQName.uri); return super.createAttrNode(attrQName); } @Override protected Element createElementNode(QName qName) { if (fixupMap.containsKey(qName.uri)) qName.uri = fixupMap.get(qName.uri); return super.createElementNode(qName); } } 

L’ailleurs, vous pouvez parsingr le

 DOMParse p = new MyDOMParser(...); p.parse(new InputSource(inputStream)); Document doc = p.getDocument(); 

Disons que vous avez votre instance de document.

 import org.dom4j.*; { static final Ssortingng YOUR_NAMESPACE_PREFIX = "PREFIX"; static final Ssortingng YOUR_NAMESPACE_URI = "URI"; Document document = ... //now get the root element Element element = document.getRootElement(); renameNamespaceRecursive(element); ... //End of this method } //the recursive method for the operation void renameNamespaceRecursive(Element element) { element.setQName(new QName(element.getName(), DocumentHelper.createNamespace(YOUR_NAMESPACE_PREFIX, YOUR_NAMESPACE_URI))); for (Iterator i = element.elementIterator(); i.hasNext();) { renameNamespaceRecursive((Element)i.next()); } } 

Cela devrait faire.

J’ai résolu en utilisant org.jdom.Element:

Java:

 import org.jdom.Element; ... Element kml = new Element("kml", "http://www.opengis.net/kml/2.2"); 

XML:

 ; ...