Remplacement rapide de nœud XML valeurs
J'ai un tas de documents XML qui contiennent des informations personnelles que j'ai besoin de le remplacer avec de fausses données. La Personne nœud contient les éléments suivants:
- uuid - requis ne doit pas être touché.
- prénom - facultatif
- nom - option
- adresse - facultatif
- personID - requis
Une personne peut s'afficher plusieurs fois, dans ce cas le même faux de données doit être utilisée, c'est à dire si deux Personne nœuds ont le même personID, elles doivent recevoir la même fausse carte d'identité.
J'ai mis en œuvre une partie de code Java qui permet de créer une arborescence DOM de la chaîne XML et remplace les nœuds avant de l'écrire à une chaîne. Cela fonctionne bien, mais depuis que j'ai tant de documents, je me demandais si il y a une approche plus rapide. Peut-être grâce à des expressions régulières ou XSLT ou quelque chose?
Voici un exemple de document:
<ADocument>
<Stuff>
...
</Stuff>
<OtherStuff>
...
</OtherStuff>
<Person>
<uuid>11111111-1111-1111-1111-111111111111</uuid>
<firstName>Some</firstName>
<lastName>Person</lastName>
<personID>111111111111</personID>
</Person>
<Person>
<uuid>22222222-2222-2222-2222-222222222222</uuid>
<firstName>Another Person</firstName>
<address>Main St. 2</address>
<personID>222222222222</personID>
</Person>
<Person>
<uuid>33333333-3333-3333-3333-333333333333</uuid>
<firstName>Some</firstName>
<lastName>Person</lastName>
<personID>111111111111</personID>
</Person>
<MoreStuff>
...
</MoreStuff>
</ADocument>
Et c'est mon actuel de mise en œuvre:
public String replaceWithFalseData(String xmlInstance) {
Document dom = toDOM(xmlInstance);
XPathExpression xPathExpression = XPathExpressionFactory.createXPathExpression("//Person");
List<Node> nodeList = xPathExpression.evaluateAsNodeList(dom);
for(Node personNode : nodeList) {
Map<String, Node> childNodes = getChildNodes(personNode);
String personID = childNodes.get("personID").getTextContent();
//Retrieve a cached fake person using the ID, or create a new one if none exists.
Person fakePerson = getFakePerson(personID);
setIfExists(childNodes.get("firstName"), fakePerson.getFirstName());
setIfExists(childNodes.get("lastName"), fakePerson.getLastName());
setIfExists(childNodes.get("address"), fakePerson.getAddress());
setIfExists(childNodes.get("personID"), fakePerson.getPersonID());
}
return toString(dom);
}
public Map<String, Node> getChildNodes(Node parent) {
Map<String, Node> childNodes = new HashMap<String, Node>();
for(Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
if(child.getLocalName() != null) {
childNodes.put(child.getLocalName(), child);
}
}
return childNodes;
}
public void setIfExists(Node node, String value) {
if(node != null) {
node.setTextContent(value);
}
}
- Par "rapide" vous entendez plus performant ou le plus élégant?
- Quelles sont les règles pour la création de faux prénom, nom, adresse et personId attributs?
- plus performant
- pour les noms et adresse, juste une chaîne de caractères arbitraire - pour personID, un de 12 caractères longue chaîne de chiffres
Vous devez vous connecter pour publier un commentaire.
Vous êtes en utilisant DOM API. Plus rapide de remplacement peut être réalisé avec Streaming API for XML (StAX) qui, dans de nombreux cas, peuvent surpasser les DOM-API basée sur:
StAX rapport à DOM
API DOM occupe plus de mémoire que StAX, ce qui peut dégrader les performances, mais est plus facile à utiliser que StAX API.
Solution de travail pour votre exemple - testé sur 150 MO fichier xml, remplacé en 10 sec:
Utilisation
persons.xml
comme entrée:La production de ce
fakePersons.xml
résultat:Je ne suis pas sûr si une transformation XSLT peut aider ici. Peut-être que mes connaissances sur XSLT n'est pas assez profonde, mais d'une transformation XSLT permet de créer une nouvelle structure XML sur la base des données d'un document XML. Il semble que vous voulez faire le contraire: en conservant la même structure, mais updateing les données sont basées sur des valeurs dynamiques. Vous pourriez avoir un moment difficile la création d'une telle XSLT.
L'optimalisation peut dépendre de beaucoup de paramètres: le nombre d'éléments par XML, la quantité de l'égalité des PersonIds dans le XML, le nombre de XMLs à traiter, ... Si vous êtes de nouveau affaire avec de gros fichiers, vous pourriez passer à un SAX mise en œuvre pour optimiser votre consommation de mémoire. Si vous re dealign avec un grand nombre de l'égalité des PersonIDs dans le même fichier XML, vous pouvez construire une partie de la mise en cache de la structure derrière votre faux de données que vous utilisez pour remplacer afin de réduire la quantité de hits sur votre DOM (vous pouvez remplacer directement le nœud avec la mise en cache nœud et écraser l'uuid avec l'original).
Si vous avez beaucoup de petits fichiers contenant des PersonIDs vous pouvez utiliser de la croix XML de mise en cache s'il est acceptable que le même faux de données peut être utilisée sur plusieurs fichiers XML.
Aussi, je crois que vous pouvez déposer l' 'setIfExists" sur le PersonID comme il est indiqué comme un champ obligatoire.
Je ne peux pas commenter sur la performance relative mais ici, c'est une transformation XSLT solution à votre problème.
Suivantes feuille de style XSLT:
génère le code XML suivant lorsqu'il est appliqué à votre exemple de document:
Merci à tous ceux qui ont contribué! J'ai couru un test de performance sur un ensemble de 2000 documents XML à l'aide de mon DOM mise en œuvre, Sergej du StAX mise en œuvre de Ben et XSLT mise en œuvre ainsi que de l'autre la mise en œuvre de la mienne, à l'aide d'expressions régulières. Les résultats sont comme suit:
Et voici le gagnant: