Un document XML peut nécessiter une mise à jour de sa structure et de ses données. Le DOM dispose de méthodes capables de remplacer et de supprimer des noeuds et de modifier des données textuelles.

La méthode removeChild() de l'objet Node supprime le noeud spécifié de la liste des enfants.

DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
DocumentBuilder analyseur = fabrique.newDocumentBuilder();
analyseur.setValidating(true);
Document doc_xml = analyseur.parse(new File("source.xml"));
Element element = doc_xml.getElementById("XSY210356");
Element racine = doc_xml.getDocumentElement();
Node noeud_sup = racine.removeChild(element);

/*Contenu du document XML :
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE liste [...]>
<liste>
  <logiciel id="CTP0124555">
    ...
  </logiciel>
  <logiciel id="XSY325684">
    ...
  </logiciel>
  <logiciel id="XWR387795">
    ...
  </logiciel>
</liste>*/

De cette manière n'importe quel noeud dans l'arborescence XML peut être supprimé. Pour un noeud textuel, il suffit de cibler l'objet contenant le texte, puis de soumettre l'enfant de ce dernier à la méthode removeChild().

NodeList commentaires = doc_xml.getElementsByTagName("commentaire");
for(int i = 0; i < commentaires.getLength(); i++){
  Node commentaire = commentaires.item(i);
  if(commentaire.hasChildNodes()){
    Node texte = commentaire.getChildNodes().item(0);
    commentaire.removeChild(texte);
  }
}

/*Tous les éléments commentaire
deviennent des éléments vides <commentaire/>
*/

Après suppression, un noeud Element peut devenir un élément vide.

for(int i = noeuds.getLength() - 1; i >= 0; i--){
  Node noeud = noeuds.item(i);
  Node noeud_sup = element.removeChild(noeud);
}
/*L'arborescence de l'élément logiciel avec id="XSY210356"
devient un élément vide <logiciel id="XSY210356"/>
*/

La méthode removeChild() est susceptible de lancer trois exceptions :

  • NO_MODIFICATION_ALLOWED_ERR est lancée si le noeud est en lecture seul.
  • NOT_FOUND_ERR est lancée si le noeud à supprimer n'est pas un enfant de ce noeud.
  • NOT_SUPPORTED_ERR est lancée si le noeud est de type Document.

Les attributs peuvent être supprimés d'un élément en utilisant les méthodes de suppression d'attributs de l'objet Element.

Element logiciel = document.getElementById("CTP0124555");
if(logiciel != null){
  Element element = logiciel.getChildNodes().item(0);
  element.removeAttribute("systeme_exploitation");
  if(!element.hasAttribute("systeme_exploitation"))
    System.out.println("L'attribut systeme_exploitation a été supprimé !");

  Node attribut = element.getAttributes().item(0);
  if(element.removeAttributeNode(attribut) != null)
    System.out.println("L'attribut " + attribut.getNodeName() +  " a été supprimé !");
}
/*Contenu du document XML :
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE liste [...]>
<liste>
  <logiciel id="CTP0124555">
    <nom>Cooktop 2.200</nom>
    ...
  </logiciel>
  <logiciel id="XSY325684">
    ...
  </logiciel>
  <logiciel id="XSY210356">
    ...
  </logiciel>
  <logiciel id="XWR387795">
    ...
  </logiciel>
</liste>*/

Une autre méthode de suppression existe, mais elle doit être employée pour un attribut situé dans un espace de noms. Il s'agît de la méthode removeAttributeNS().

La méthode replaceChild() remplace un noeud par un autre.

NodeList elements = document.getElementsByTeagName("commentaire");
Node element1 = elements.item(0);
Node element2 = elements.item(elements.getLength() - 1);
Node texte1 = element1.getFirstChild().cloneNode();
Node texte2 = element2.getFirstChild().cloneNode();
Node nouv_noeud1 = element1.replaceChild(
                              texte2, 
                              element1.getFirstChild());
Node nouv_noeud2 = element2.replaceChild(
                              texte1, 
                              element2.getFirstChild());

/*Contenu du document :
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE liste [...]>
<liste>
  <logiciel id="CTP0124555">
    ...
    <commentaire>
      Permet de creer des documents XML.
    </commentaire>
    ...
  </logiciel>
  <logiciel id="XSY325684">
    ...
  </logiciel>
  <logiciel id="XSY210356">
    ...
  </logiciel>
  <logiciel id="XWR387795">
    ...
    <commentaire>
      Un editeur XML, XSLT, XPath et DTD puissant et totalement gratuit.
    </commentaire>
  </logiciel>
    ...
</liste>*/

Cette méthode peut lancer plusieurs exceptions :

  • NO_MODIFICATION_ALLOWED_ERR est lancée si le noeud est en lecture seule ou si le parent précédent du noeud à insérer est en lecture seule.
  • HIERARCHY_REQUEST_ERR est lancée si le noeud est d'un type qui n'autorise pas les enfants du type du nouveau noeud, ou si le noeud à insérer est un des ancêtres de ce noeud ou ce noeud lui-même.
  • WRONG_DOCUMENT_ERR est lancée si le nouveau noeud provient d'un document différent que celui qui l'a créé.
  • NOT_FOUND_ERR est lancée si l'ancien noeud n'est pas un enfant de ce noeud.
  • NOT_SUPPORTED_ERR est lancée si le noeud est du type Document.

Les chaînes de caractères présentes dans les noeuds textuels peuvent être modifiées complètement ou partiellement. La classe CharacterData propose des méthodes de modification du contenu textuel d'un noeud.

DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
DocumentBuilder analyseur = fabrique.newDocumentBuilder();
analyseur.setValidating(true);
Document doc_xml = analyseur.parse(new File("source.xml"));
NodeList logiciels = doc_xml.getElementsByTagName("logiciel");
for(int i = 0; i < logiciels.getLength(); i++){
  Node logiciel = logiciels.item(i);
  NodeList noms = logiciel.getElementsByTagName("nom");
  Node nom = noms.item(0).getFirstChild();
  NodeList commentaires = logiciel.getElementsByTagName("commentaire");
  Node commentaire = commentaires.item(0).getFirstChild();
  //Insertion du nom devant le commentaire
  commentaire.insertData(0, " : ");
  commentaire.insertData(0, nom.getNodeValue());
  NodeList colprix = logiciel.getElementsByTagName("prix");
  Node prix = colprix.item(0).getFirstChild();
  int pos = commentaire.getNodeValue().indexOf(".");
  int taille = commentaire.getNodeValue().length();
  //Suppression du point terminal et des espaces blancs
  commentaire.deleteData(pos , taille - pos);
  //Ajout du prix entre parenthèses
  commentaire.appendData("(");
  commentaire.appendData(prix.getNodeValue());
  commentaire.appendData(").");
}

/*Affiche :
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE liste [...]>
<liste>
  <logiciel id="CTP0124555">
    ...
    <commentaire>
      Cooktop 2.200
      : 
      Un editeur XML, XSLT, XPath et DTD puissant et totalement gratuit
      (00.00).
    </commentaire>
    ...
  </logiciel>
  <logiciel id="XSY325684">
    ...
    <commentaire>
      XML Spy 4.1
      : 
      Un editeur XML desormais mature
      (199,00).
    </commentaire>
    ...
  </logiciel>
  <logiciel id="XSY210356">
    ...
    <commentaire>
      XML Spy 4.1 B2B Server
     : 
      La version 4 en version Business to business
    (1 999,00).
    </commentaire>
    ...
  </logiciel>
  <logiciel id="XWR387795">
    ...
    <commentaire>
      XMLwriter v1.21
      : 
      Permet de creer des documents XML
      (75,00).
    </commentaire>
    ...
  </logiciel>
</liste>
*/

for(int i = 0; i < logiciels.getLength(); i++){
  Node logiciel = logiciel.item(i);
  NodeList noms = logiciel.getElementsByTagName("nom");
  Node nom = noms.item(0).getFirstChild();
  NodeList commentaires = logiciel.getElementsByTagName("commentaire");
  Node commentaire = commentaires.item(0).getFirstChild();
  int pos = commentaire.getNodeValue().indexOf(":");
  //Suppression du nom du logiciel
  commentaire.deleteData(0, pos + 1);
  pos = commentaire.getNodeValue().indexOf("(");
  taille = commentaire.getNodeValue().getLength();
  //Remplacement du prix entre parenthèses par un point terminal
  commentaire.replaceData(pos, taille - pos, ".");
}

//Retour à la source d'origine

Les méthodes appendData(), deleteData(), insertData(), replaceData() et substringData() s'appliquent à tous les noeuds héritant de la classe CharacterData, en l'occurrence Text, Comment et CDataSection. La méthode setData() assigne une chaîne de caractères au noeud textuel. Si ce dernier possèdait déjà un contenu, celui-ci serait supprimé et remplacé par le nouveau texte.

La valeur des attributs est fixée par la méthode setValue() de la classe Attr ou setNodeValue() de la classe Node.

public class Attribut {
  public static void main(String[] args) {
    try {
      URL url = new URL("http://laltruiste.com/coursjava/exemples/logitheque.xml");
      InputSource source = new InputSource(url.openStream());
      XPathFactory fabrique = XPathFactory.newInstance();
      XPath environnement = fabrique.newXPath();
      XPathExpression expression = environnement.compile("//logiciel/prix");
      NodeList colPrix = (NodeList) 
                       expression.evaluate(source, XPathConstants.NODESET);
      for (int i = 0; i < colPrix.getLength(); i++) {
        Element noeud = (Element) colPrix.item(i);
        Attr monnaie = noeud.getAttributeNode("monnaie");
        if (monnaie.getNodeValue().equals("FRF")) {
          monnaie.setValue("€");
          String valeur = noeud.getFirstChild().getNodeValue()
                                     .replaceAll(" ", "").replaceAll(",", ".");
          double nb = new Double(valeur).doubleValue() / 6.55957;
          noeud.getFirstChild().setNodeValue(String.valueOf(nb));
        }
      }
    }
    catch (IOException e) {
      e.printStackTrace();
    }
    catch (XPathExpressionException e) {
      e.printStackTrace();
    }
  }
}