inserire/sostituire il tag XML in XmlDocument
Domanda
Ho un XmlDocument
in Java, creato con il Weblogic XmlDocument
parser.
Voglio sostituire il contenuto di un tag in this XMLDocument
con i miei dati, oppure inserisci il tag se non c'è.
<customdata>
<tag1 />
<tag2>mfkdslmlfkm</tag2>
<location />
<tag3 />
</customdata>
Ad esempio, voglio inserire un URL nel tag location:
<location>http://something</location>
ma per il resto lascia l'XML così com'è.
Attualmente utilizzo a XMLCursor
:
XmlObject xmlobj = XmlObject.Factory.parse(a.getCustomData(), options);
XmlCursor xmlcur = xmlobj.newCursor();
while (xmlcur.hasNextToken()) {
boolean found = false;
if (xmlcur.isStart() && "schema-location".equals(xmlcur.getName().toString())) {
xmlcur.setTextValue("http://replaced");
System.out.println("replaced");
found = true;
} else if (xmlcur.isStart() && "customdata".equals(xmlcur.getName().toString())) {
xmlcur.push();
} else if (xmlcur.isEnddoc()) {
if (!found) {
xmlcur.pop();
xmlcur.toEndToken();
xmlcur.insertElementWithText("schema-location", "http://inserted");
System.out.println("inserted");
}
}
xmlcur.toNextToken();
}
Ho provato a trovare un "veloce" xquery
modo per farlo dal momento che XmlDocument
ha un execQuery
metodo, ma non l'ho trovato molto semplice.
Qualcuno ha un modo migliore di questo?Sembra un po' elaborato.
Soluzione
Che ne dici di un approccio basato su XPath?Mi piace questo approccio perché la logica è semplicissima da capire.Il codice è praticamente autodocumentante.
Se il tuo documento xml è disponibile come oggetto org.w3c.dom.Document (come ritorna la maggior parte dei parser), allora potresti fare qualcosa di simile a quanto segue:
// get the list of customdata nodes
NodeList customDataNodeSet = findNodes(document, "//customdata" );
for (int i=0 ; i < customDataNodeSet.getLength() ; i++) {
Node customDataNode = customDataNodeSet.item( i );
// get the location nodes (if any) within this one customdata node
NodeList locationNodeSet = findNodes(customDataNode, "location" );
if (locationNodeSet.getLength() > 0) {
// replace
locationNodeSet.item( 0 ).setTextContent( "http://stackoverflow.com/" );
}
else {
// insert
Element newLocationNode = document.createElement( "location" );
newLocationNode.setTextContent("http://stackoverflow.com/" );
customDataNode.appendChild( newLocationNode );
}
}
Ed ecco il metodo di supporto findNodes che esegue la ricerca XPath.
private NodeList findNodes( Object obj, String xPathString )
throws XPathExpressionException {
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression expression = xPath.compile( xPathString );
return (NodeList) expression.evaluate( obj, XPathConstants.NODESET );
}
Altri suggerimenti
Che ne dici di un approccio orientato agli oggetti?È possibile deserializzare l'XML in un oggetto, impostare il valore della posizione sull'oggetto, quindi serializzare nuovamente in XML.
XStream lo rende davvero facile.
Ad esempio, definiresti l'oggetto principale, che nel tuo caso è CustomData (sto utilizzando i campi pubblici per mantenere semplice l'esempio):
public class CustomData {
public String tag1;
public String tag2;
public String location;
public String tag3;
}
Quindi inizializzi XStream:
XStream xstream = new XStream();
// if you need to output the main tag in lowercase, use the following line
xstream.alias("customdata", CustomData.class);
Ora puoi costruire un oggetto da XML, impostare il campo location sull'oggetto e rigenerare l'XML:
CustomData d = (CustomData)xstream.fromXML(xml);
d.location = "http://stackoverflow.com";
xml = xstream.toXML(d);
Come ti sembra?
Se non conosci lo schema, la soluzione XStream probabilmente non è la strada da percorrere.Almeno XStream è sul tuo radar adesso, potrebbe tornare utile in futuro!
Dovresti essere in grado di farlo con query
Tentativo
fn:replace(string,pattern,replace)
Sono nuovo a xquery e ho trovato che sia un linguaggio di query doloroso con cui lavorare, ma funziona abbastanza bene una volta superata la curva di apprendimento iniziale.
Vorrei ancora che ci fosse un modo più semplice che fosse altrettanto efficiente?