Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Ajout de noeud dans saxon via XPATH + API Saxon HE 9.3 ne fonctionne pas

7 réponses
Avatar
ALaRechercheDuTempsPerdu
Bonjour,

J'execute une requ=EAte XPATH pour selectionner un noeud depuis un
document source
Modifier certains attributs via mon appli java
Injecter le noeud r=E9sultant dans un doc XML cible.

Je pr=E9cise que je n'utilise pas XSLT sciemment :)

Mon probl=E8me est le suivant : au moment de s=E9rialiser mon nouveau
document, le document enregsitr=E9 est identique =E0 l'ancien, comme si
l'appel =E0 Append n'avait rien fait.

Voici le code :

XdmValue source =3D parseXmlDocument(xmlSource);
logger.info("XML parsed.");

try
{
// Fetch node to append
String xpathQuery =3D "/client/voiture/mode[@name=3D'Chevrolet']";
XPathExecutable _XPathExecutable =3D getXpathEvaluator(xpathQuery);
XPathSelector xps =3D _XPathExecutable.load();
xps.setContextItem((XdmItem) source);
XdmValue child =3D xps.evaluate();
logger.info("Child node fetched.");

// Append node to source.
XdmValue newDocumentRoot =3D source.append(child);
logger.info("Child node appended.");

// Save to disk.
Serializer serializer =3D getSaxonSerializer(xmlSource);
XdmNode newDocumentRootNode =3D (XdmNode) newDocumentRoot.itemAt(0);
serializer.serializeNode(newDocumentRootNode);
logger.info("file saved.");

Est-ce quelqu'un pourrait m'expliquer ce que je fais mal ?

Merci pour vos lumi=E8res !

7 réponses

Avatar
Alain Ketterlin
ALaRechercheDuTempsPerdu writes:

J'execute une requête XPATH pour selectionner un noeud depuis un
document source
Modifier certains attributs via mon appli java
Injecter le noeud résultant dans un doc XML cible.

Je précise que je n'utilise pas XSLT sciemment :)



En fait tu n'utilises pas XSLT ici, seulement XPath et ce n'est pas le
problème.

XdmValue source = parseXmlDocument(xmlSource);



source est un noeud document (son premier fils est l'élément raci ne)
= (DOC (client ...))

// Append node to source.
XdmValue newDocumentRoot = source.append(child);



un nouveau noeud document avec deux éléments racines successifs
= (DOC (client ...) (mode ...))

(au passage, ça ne devrait pas être autorisé, avec un DOM co nforme tu
devrais prendre une exception)

XdmNode newDocumentRootNode = (XdmNode) newDocumentRoot.itemAt(0);



récupère l'ancienne racine (qui est toujours là).
= (client ...)

-- Alain.
Avatar
Yliur
Bonjour

Mon problème est le suivant : au moment de sérialiser mon nouveau
document, le document enregsitré est identique à l'ancien, comme si
l'appel à Append n'avait rien fait.



Je ne connais pas la bibliothèque mais quelques remarques, sait-on
jamais...

XdmValue source = parseXmlDocument(xmlSource);
logger.info("XML parsed.");

try
{
// Fetch node to append
String xpathQuery = "/client/voiture/mode[@name='Chevrolet']";
XPathExecutable _XPathExecutable = getXpathEvaluator(xpathQuery);
XPathSelector xps = _XPathExecutable.load(); xps.setContextItem((XdmItem) source);
XdmValue child = xps.evaluate();
logger.info("Child node fetched.");



Bon, là pour la forme on pourrait vérifier que le bon noeud a été
récupéré.

// Append node to source.
XdmValue newDocumentRoot = source.append(child);
logger.info("Child node appended.");



Est-il possible de vérifier que le noeud fils a été correctement
inséré ?

// Save to disk.
Serializer serializer = getSaxonSerializer(xmlSource);



Je suppose que xmlSource est simplement le chemin du fichier source ?

XdmNode newDocumentRootNode = (XdmNode) newDocumentRoot.itemAt(0);



Pourquoi récupérer un élément ? Est-ce qu'il ne faut pas sauver la
racine ? Quel est cet élément à l'emplacement 0 ? Est-ce la bonne
racine ? Est-ce que l'élément ajouté ne se trouve pas à côté (à
l'emplacement 1) ?

serializer.serializeNode(newDocumentRootNode);
logger.info("file saved.");



Voilà, en espérant qu'un peu de trace permette de résoudre le
problème :) .
Avatar
Yliur
Ah... grillé par un voisin :)
Avatar
ALaRechercheDuTempsPerdu
Bonjour,

J'ai continué à chercher :)
Pour la remarque sur le fait que je me retrouve avec 2 éléments
racine, ce qui est invalide, c'est tout à fait exact !

Du coup, j'ai changé mon fusil d'épaule :

1 Chargement d'un DOM Source classique
2 Wrap dans un Saxon XdmItem du DomSourcepour faire la requete XPath
3 Injection du noeud récupéré dans mon DomSource d'origine après
modification du noeud.
4 Sauvegarde du nouveau domsource (celui de départ + le noeuf
modifié).

Je bloque sur le 3 :
Comment transformer mon XdmValue en Node pour pouvoir faire le
appendChild ?

Extarct de code :
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
javax.xml.parsers.DocumentBuilder builder =
factory.newDocumentBuilder();
Document domRoot = builder.parse(xmlSource);

String msg = String.format("%s has been read.",
xmlSource.getName());
logger.info(msg);


// Injection dom source into saxon framework
DocumentBuilder saxonBuilder = processor.newDocumentBuilder();
saxonBuilder.setTreeModel(TreeModel.LINKED_TREE);
Source s = new DOMSource(domRoot);
XdmNode saxonDocument = saxonBuilder.build(s);

String xpathQuery = "/chevrolet[1]";
XPathExecutable _XPathExecutable = getXpathEvaluator(xpathQuery);
XPathSelector xps = _XPathExecutable.load();
xps.setContextItem(saxonDocument);
XdmNode child = (XdmNode)xps.evaluateSingle();

// Append node to source.
//String msg = String.format("Collection size before : %d",
source.size());
//logger.info(msg);

// C'est la suite qui bloque, au moment d'injecter le résultat de la
requête, j'arrive pas à trouver le chemin pour caster :(
NodeInfo ni = child.getUnderlyingNode();

domRoot.adoptNode(ni);

Merci pour votre aide en tout cas !
Avatar
Alain Ketterlin
ALaRechercheDuTempsPerdu writes:

1 Chargement d'un DOM Source classique
2 Wrap dans un Saxon XdmItem du DomSourcepour faire la requete XPath
3 Injection du noeud récupéré dans mon DomSource d'origine après
modification du noeud.



Tu n'as toujours pas dit à quel endroit tu voulais insérer le noe ud.
D'autre part, le même noeud ne peut pas apparaître deux fois dans un
arbre (par définition) : il faudra donc le cloner, puis insérer s on
clone.

4 Sauvegarde du nouveau domsource (celui de départ + le noeuf
modifié).

Je bloque sur le 3 :
Comment transformer mon XdmValue en Node pour pouvoir faire le
appendChild ?



Il n'y a aucune raison que ce soit possible. Après :

XdmNode saxonDocument = saxonBuilder.build(s);



il n'est pas sûr que les nodes saxon fassent encore référenc e aux nodes
DOM. Il vaudrait mieux choisir l'un ou l'autre.

-- Alain.
Avatar
ALaRechercheDuTempsPerdu
On 15 juin, 15:45, Alain Ketterlin
wrote:
ALaRechercheDuTempsPerdu writes:
> 1 Chargement d'un DOM Source classique
> 2 Wrap dans un Saxon XdmItem du DomSourcepour faire la requete XPath
> 3 Injection du noeud récupéré dans mon DomSource d'origine aprè s
> modification du noeud.

Tu n'as toujours pas dit à quel endroit tu voulais insérer le noeud.
D'autre part, le même noeud ne peut pas apparaître deux fois dans un
arbre (par définition) : il faudra donc le cloner, puis insérer son
clone.

> 4 Sauvegarde du nouveau domsource (celui de départ + le noeuf
> modifié).

> Je bloque sur le 3 :
> Comment transformer mon XdmValue en Node pour pouvoir faire le
> appendChild ?

Il n'y a aucune raison que ce soit possible. Après :

>XdmNodesaxonDocument = saxonBuilder.build(s);

il n'est pas sûr que les nodes saxon fassent encore référence aux n odes
DOM. Il vaudrait mieux choisir l'un ou l'autre.

-- Alain.



Ah exact, je vais l'inserer dans un des enfants du dom, pour cela, je
comptais faire un getChild sur le modèle DOM.
Pour le point du clone, en réalité, le noeud copié provient d'un autr e
document source sur lequel j'ai fait une requete XPath.

Pour utiliser le saxon builder c'est bonne idée, j'ai juste un pb pour
faire l'append sur le child correct.
Peut-être que je devrai faire une requête xpath pour déterminer le
point d'insertion et faire l'append dessus: j'obtiens alors e2.

Mais j'aurai tjs le même pb: comment rattacher le nouvel element e2
dans le document saxon :(
Avatar
ALaRechercheDuTempsPerdu
Bon, après une tentative infructueuse d'utiliser ceci :
Processor proc = new Processor(false);

Serializer serializer = getSaxonSerializer(new File("xmlConfDir",
"output.xml"));
proc.writeXdmValue(child, dest);

je vais sérialiser mon child en mémoire, construire un nouveau doc xml
avec ce child puis l'importer dans mon doc destination.
quelle est la classe de output stream pour travailler en mémoire
déjà .... hmm javadoc to my rescue :)