parseo - Obtener el XML interno de un nodo como String en DOM Java
read xml java 8 (10)
Aquí hay una solución alternativa para extraer el contenido de org.w3c.dom.Node. Esta solución también funciona si el contenido del nodo no contiene etiquetas xml:
private static String innerXml(Node node) throws TransformerFactoryConfigurationError, TransformerException {
StringWriter writer = new StringWriter();
String xml = null;
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(node), new StreamResult(writer));
// now remove the outer tag....
xml = writer.toString();
xml = xml.substring(xml.indexOf(">") + 1, xml.lastIndexOf("</"));
return xml;
}
Tengo un XML org.w3c.dom.Node que se ve así:
<variable name="variableName">
<br /><strong>foo</strong> bar
</variable>
¿Cómo obtengo la parte del <br /><strong>foo</strong> bar
como cadena?
El mismo problema. Para resolverlo escribí esta función de ayudante:
public String innerXml(Node node) {
DOMImplementationLS lsImpl = (DOMImplementationLS)node.getOwnerDocument().getImplementation().getFeature("LS", "3.0");
LSSerializer lsSerializer = lsImpl.createLSSerializer();
NodeList childNodes = node.getChildNodes();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < childNodes.getLength(); i++) {
sb.append(lsSerializer.writeToString(childNodes.item(i)));
}
return sb.toString();
}
Extendiendo la respuesta de Andrey M, tuve que modificar ligeramente el código para obtener el documento DOM completo. Si solo usas el
NodeList childNodes = node.getChildNodes();
No incluyó el elemento raíz para mí. Para incluir el elemento raíz (y obtener el documento completo .xml) utilicé:
public String innerXml(Node node) {
DOMImplementationLS lsImpl = (DOMImplementationLS)node.getOwnerDocument().getImplementation().getFeature("LS", "3.0");
LSSerializer lsSerializer = lsImpl.createLSSerializer();
lsSerializer.getDomConfig().setParameter("xml-declaration", false);
StringBuilder sb = new StringBuilder();
sb.append(lsSerializer.writeToString(node));
return sb.toString();
}
La mejor solución hasta el momento, la de Andrey M, necesita una implementación específica que pueda causar problemas en el futuro. Este es el mismo enfoque, pero con cualquier cosa que JDK le dé para hacer la serialización (es decir, qué está configurado para ser utilizado).
public static String innerXml(Node node) throws Exception
{
StringWriter writer = new StringWriter();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
NodeList childNodes = node.getFirstChild().getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
transformer.transform(new DOMSource(childNodes.item(i)), new StreamResult(writer));
}
return writer.toString();
}
Si está procesando un documento en lugar de un nodo, debe tener un nivel de profundidad y usar node.getFirstChild().getChildNodes();
Pero, para hacerlo más robusto, debe encontrar el primer Elemento, no solo dar por sentado que solo hay un nodo. XML tiene que tener un único elemento raíz, pero puede tener múltiples nodos, incluidos comentarios, entidades y texto en blanco.
Node rootElement = docRootNode.getFirstChild();
while (rootElement != null && rootElement.getNodeType() != Node.ELEMENT_NODE)
rootElement = rootElement.getNextSibling();
if (rootElement == null)
throw new RuntimeException("No root element found in given document node.");
NodeList childNodes = rootElement.getChildNodes();
Y si debería recomendar una biblioteca para manejarlo, pruebe JSoup, que es principalmente para HTML, pero también funciona con XML . Aunque no lo he probado.
Document doc = Jsoup.parse(xml, "", Parser.xmlParser());
fileContents.put(Attributes.BODY, document.body().html());
// versus: document.body().outerHtml()
No hay un método simple en org.w3c.dom.Node
para esto. getTextContent()
proporciona el texto de cada nodo secundario concatenado. getNodeValue()
le dará el texto del nodo actual si es un nodo de Attribute
, CDATA
o Text
. Por lo tanto, necesitaría serializar el nodo utilizando una combinación de getChildNodes()
, getNodeName()
y getNodeValue()
para construir la cadena.
También puede hacerlo con una de las diversas bibliotecas de serialización XML que existen. Hay XStream
o incluso JAXB. Esto se discute aquí: ¿ serialización XML en Java?
Quiero extender la muy buena respuesta de Andrey M .:
Puede suceder que un nodo no sea serializable y esto da como resultado la siguiente excepción en algunas implementaciones:
org.w3c.dom.ls.LSException: unable-to-serialize-node:
unable-to-serialize-node: The node could not be serialized.
Tuve este problema con la implementación " org.apache.xml.serialize.DOMSerializerImpl.writeToString (DOMSerializerImpl) " ejecutándose en Wildfly 13.
Para resolver este problema, sugeriría cambiar un poco el ejemplo de código de Andrey M.
private static String innerXml(Node node) {
DOMImplementationLS lsImpl = (DOMImplementationLS) node.getOwnerDocument().getImplementation().getFeature("LS", "3.0");
LSSerializer lsSerializer = lsImpl.createLSSerializer();
lsSerializer.getDomConfig().setParameter("xml-declaration", false);
NodeList childNodes = node.getChildNodes();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < childNodes.getLength(); i++) {
Node innerNode = childNodes.item(i);
if (innerNode!=null) {
if (innerNode.hasChildNodes()) {
sb.append(lsSerializer.writeToString(innerNode));
} else {
sb.append(innerNode.getNodeValue());
}
}
}
return sb.toString();
}
También agregué el comentario de Nyerguds. Esto funciona para mí en wildfly 13.
Si está utilizando jOOX , puede envolver su nodo en una sintaxis de tipo jquery y simplemente invocar toString()
en él:
$(node).toString();
Utiliza un transformador de identidad internamente, así:
ByteArrayOutputStream out = new ByteArrayOutputStream();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
Source source = new DOMSource(element);
Result target = new StreamResult(out);
transformer.transform(source, target);
return out.toString();
Si no desea recurrir a bibliotecas externas, la siguiente solución puede ser útil. Si tiene un nodo <parent><child name="Nina"/></parent>
y desea extraer los elementos secundarios del elemento primario, proceda de la siguiente manera:
StringBuilder resultBuilder = new StringBuilder();
// Get all children of the given parent node
NodeList children = parent.getChildNodes();
try {
// Set up the output transformer
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer trans = transfac.newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter stringWriter = new StringWriter();
StreamResult streamResult = new StreamResult(stringWriter);
for (int index = 0; index < children.getLength(); index++) {
Node child = children.item(index);
// Print the DOM node
DOMSource source = new DOMSource(child);
trans.transform(source, streamResult);
// Append child to end result
resultBuilder.append(stringWriter.toString());
}
} catch (TransformerException e) {
//Error handling goes here
}
return resultBuilder.toString();
Sobre la base de la solución de Lukas Eder, podemos extraer innerXml como en .NET como se muestra a continuación
public static String innerXml(Node node,String tag){
String xmlstring = toString(node);
xmlstring = xmlstring.replaceFirst("<[/]?"+tag+">","");
return xmlstring;
}
public static String toString(Node node){
String xmlString = "";
Transformer transformer;
try {
transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
//transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult result = new StreamResult(new StringWriter());
xmlString = nodeToStream(node, transformer, result);
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (Exception ex){
ex.printStackTrace();
}
return xmlString;
}
Ex:
If Node name points to xml with string representation "<Name><em>Chris</em>tian<em>Bale</em></Name>"
String innerXml = innerXml(name,"Name"); //returns "<em>Chris</em>tian<em>Bale</em>"
Tuve el problema con la última respuesta de que el método ''nodeToStream ()'' no está definido; por lo tanto, mi versión aquí:
public static String toString(Node node){
String xmlString = "";
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
//transformer.setOutputProperty(OutputKeys.INDENT, "yes");
Source source = new DOMSource(node);
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
transformer.transform(source, result);
xmlString = sw.toString ();
} catch (Exception ex) {
ex.printStackTrace ();
}
return xmlString;
}