L'objectif de ce code est le parcours d'un arbre principal pour y détecter un noeud particulier et le mettre à jour avec de nouvelles données XML.
Dans cette exemple l'arborescence d'origine ($xp) est lue jusqu'à ce que la pseudo ligne <Domain Name="DOIN7L9R"><Application Name="CAC07015108"> soit détectée.
Le noeud détecté est alors fusionné avec le nouveau noeud ($insert) de la façon suivante :
- si les étiquettes (ici <Domain>) sont identiques, les attributs sont ajoutés ou mis à jour sur la base des nouvelles valeurs.
- si l'étiquette est différente, la nouvelle étiquette est ajoutée après (insertAfter) l'étiquette courante.
- si l'étiquette ajoutée contient des fils (getChildNodes != null), ses fils sont ajoutés (appendChild) au noeud courant.
#!/usr/bin/perl -w
#
use XML::
XPath::
XMLParser;
use XML::
XPath::
Node ':node_keys';
$xp = XML::
XPath::
XMLParser->
new(xml=>
"<Domain Name=\"DOIN7L9R\"><Application Name=\"CAC07015108\"><EJBComponent Name=\"servicecache-ejb-1.3.0.jar\" /><WebAppComponent Name=\"/CAC01000004/servicecache\" /></Application><Application Name=\"CAC07015100\"><EJBComponent Name=\"servicecache-ejb-1.3.0.jar\" /><WebAppComponent Name=\"/CAC07015100/servicecache\" /></Application></Domain>");
$insert=XML::
XPath::
XMLParser->
new(xml=>
"<Application Name=\"CAC07015108\" Name3=\"ff\" Name2=\"ff\"><test/></Application>");
my $root =
$xp->
parse;
$i=
0;
print "#####avant\n";
Show
($root,
0);
print "\n#####fusion avec\n";
Show
($insert->
parse,
0);
print "\n#####fusion ...\n";
Walk
($root,
"");
print "\n#####apres\n";
Show
($root,
0);
# affichage du contenu XML
sub Show
{
my $root =
shift;
my $level =
shift;
foreach $child ($root->
getChildNodes){
for (my $a=
0;
$a<
$level;
$a++
){print " ";
}
print "<".
$child->
getName;
foreach $attrib ($child->
getAttributeNodes){
print $attrib->
toString;
}
print ">\n";
Show
($child,
$level+
1);
for ($a=
0;
$a<
$level;
$a++
){print " ";
}
print "</".
$child->
getName.
">\n";
}
}
#Parcours de l'arborescence XML
sub Walk
{
my $root =
shift;
my $XMLParentString =
shift;
foreach $node ($root->
getChildNodes){
if ($node->
getNodeType == ELEMENT_NODE
()){
$XMLString =
$XMLParentString . GetTextNode
($node);
# test de $XMLString
print $XMLString.
"\n";
# l'événement recherché est trouvé
if($XMLString eq
"<Domain Name=\"DOIN7L9R\"><Application Name=\"CAC07015108\">"){
$newnodes=
($insert)->
parse;
# L'arborescence XML ne peut avoir qu'une seule racine donc un seul fils
$newnode =
$newnodes->
getChildNode(1);
if ($newnode->
getName ne $node->
getName){
$root->
insertAfter($newnodes,
$node);
}
else{
#
# Fusion des attributs du node courant avec le nouveau
#
$isNew =
0;
$isMod =
0;
foreach $newattrib ($newnode->
getAttributes){
$Traitement=
0;
foreach $attrib ($node->
getAttributes){
if($attrib->
getName eq
$newattrib->
getName){
$Traitement =
1;
if($attrib->
getNodeValue ne $newattrib->
getNodeValue){
$attrib->
setNodeValue($newattrib->
getNodeValue);
}
}
}
if( not $Traitement){
$attrib=XML::
XPath::
Node::
Attribute->
new($newattrib->
getName,
$newattrib->
getNodeValue);
$node->
appendAttribute($attrib);
}
}
#
# ajout des fils du nouveau node au node courant
#
foreach $childnode ($newnode->
getChildNodes){
$node->
appendChild ( $childnode );
}
}
}
Walk
($node,
$XMLString);
}
}
}
# Fonction permettant d'afficher le node courant précédé tous ses pères
sub GetTextNode
{
my $node =
shift(@_);
my $result=
"<".
$node->
getName;
sub backwards
{ $a->
getName cmp $b->
getName;
}
my @Attributes =
sort backwards
$node->
getAttributes;
foreach my $attrib (@Attributes){
$result=
$result.
" ".
$attrib->
getName.
"=\"".
$attrib->
getNodeValue.
"\"";
}
$result=
$result.
">";
return $result;
}
Donnera cette sortie
#####avant
<Domain Name="DOIN7L9R">
<Application Name="CAC07015108">
<EJBComponent Name="servicecache-ejb-1.3.0.jar">
</EJBComponent>
<WebAppComponent Name="/CAC01000004/servicecache">
</WebAppComponent>
</Application>
<Application Name="CAC07015100">
<EJBComponent Name="servicecache-ejb-1.3.0.jar">
</EJBComponent>
<WebAppComponent Name="/CAC07015100/servicecache">
</WebAppComponent>
</Application>
</Domain>
#####fusion avec
<Application Name="CAC07015108" Name3="ff" Name2="ff">
<test>
</test>
</Application>
#####fusion ...
<Domain Name="DOIN7L9R">
<Domain Name="DOIN7L9R"><Application Name="CAC07015108">
<Domain Name="DOIN7L9R"><Application Name="CAC07015108"><EJBComponent Name="servicecache-ejb-1.3.0.jar">
<Domain Name="DOIN7L9R"><Application Name="CAC07015108"><WebAppComponent Name="/CAC01000004/servicecache">
<Domain Name="DOIN7L9R"><Application Name="CAC07015108"><test>
<Domain Name="DOIN7L9R"><Application Name="CAC07015100">
<Domain Name="DOIN7L9R"><Application Name="CAC07015100"><EJBComponent Name="servicecache-ejb-1.3.0.jar">
<Domain Name="DOIN7L9R"><Application Name="CAC07015100"><WebAppComponent Name="/CAC07015100/servicecache">
#####apres
<Domain Name="DOIN7L9R">
<Application Name="CAC07015108" Name3="ff" Name2="ff">
<EJBComponent Name="servicecache-ejb-1.3.0.jar">
</EJBComponent>
<WebAppComponent Name="/CAC01000004/servicecache">
</WebAppComponent>
<test>
</test>
</Application>
<Application Name="CAC07015100">
<EJBComponent Name="servicecache-ejb-1.3.0.jar">
</EJBComponent>
<WebAppComponent Name="/CAC07015100/servicecache">
</WebAppComponent>
</Application>
</Domain>