Leer un valor de un XML con indexOf y substring, o fabricar el documento sumando cadenas, parece más rápido que usar un analizador. Funciona con el primer ejemplo que pruebas y falla con el tercero. Lo comprobamos con seis casos, todos XML válidos.
También te puede interesar
Leer a mano
Esta es la versión que suele aparecer, con el error que trae casi siempre:
String extraer(String xml) {
int inicio = xml.indexOf("<nombre>");
int fin = xml.indexOf("</nombre>");
return xml.substring(inicio, fin);
}Devuelve <nombre>Ana: indexOf da la posición donde empieza la etiqueta, y hay que saltársela. Corregido eso, la probamos con seis documentos que cualquier analizador lee sin problema:
String[] casos = {
"<persona><nombre>Ana</nombre></persona>",
"<persona><nombre>Gómez & Hijos</nombre></persona>",
"<persona><nombre><![CDATA[<b>Ana</b>]]></nombre></persona>",
"<persona><nombre >Ana</nombre></persona>",
"<persona>\n <!-- <nombre>viejo</nombre> -->\n <nombre>Ana</nombre>\n</persona>",
"<p:persona xmlns:p=\"urn:x\"><p:nombre>Ana</p:nombre></p:persona>",
};java AMano.javaoriginal: [<nombre>Ana] [Ana] [Gómez & Hijos] [<![CDATA[<b>Ana</b>]]>] [a><nombre >Ana] [viejo] excepción: Range [7, -1) out of bounds for length 63
| Caso | Resultado a mano | Qué pasó |
|---|---|---|
| Simple | Ana | Bien |
| Con una entidad | Gómez & Hijos | No traduce & a & |
| Con CDATA | <![CDATA[…]]> | Devuelve el envoltorio en vez del contenido |
| Con un espacio en la etiqueta | a><nombre >Ana | <nombre > es válido, pero indexOf no lo encuentra y devuelve basura |
| Con un comentario delante | viejo | Lee el nombre que estaba comentado |
| Con espacio de nombres | excepción | <p:nombre> no coincide y el programa se cae |
Cinco de seis mal, y lo peor es que solo uno avisa. Los demás devuelven un valor equivocado sin ningún error.
Leer con un analizador
El JDK trae uno, así que no hace falta añadir ninguna dependencia:
String nombre(String xml) throws Exception {
var f = DocumentBuilderFactory.newInstance();
f.setNamespaceAware(true);
var doc = f.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
var nodos = doc.getElementsByTagNameNS("*", "nombre");
return nodos.getLength() == 0 ? null : nodos.item(0).getTextContent();
}java ConParser.java[Ana] [Gómez & Hijos] [<b>Ana</b>] [Ana] [Ana] [Ana]
Los seis bien. El analizador traduce las entidades, abre el CDATA, ignora los comentarios y entiende los espacios de nombres (por eso se activa setNamespaceAware y se busca con "*").
Escribir a mano
Construir el documento concatenando tiene el problema contrario: hay caracteres que en XML tienen significado y deben escaparse.
String aMano(String nombre, String atributo) {
return "<root>"
+ "<nombre atr=\"" + atributo + "\">"
+ nombre
+ "</nombre>"
+ "</root>";
}Con nombre = "Gómez & Hijos <S.A.>" y un atributo con comillas, el resultado ni siquiera es XML:
salida<root><nombre atr="dijo "hola"">Gómez & Hijos <S.A.></nombre></root> [Fatal Error] :1:26: Element type "nombre" must be followed by either attribute specifications, ">" or "/>". al leerlo: Element type "nombre" must be followed by either attribute specifications, ">" or "/>".
La línea [Fatal Error] la escribe el analizador por su cuenta en la salida de errores, antes de lanzar la excepción. Este es el error que verá quien reciba el archivo.
Escribir con el DOM
var doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
var root = doc.createElement("root");
var n = doc.createElement("nombre");
n.setAttribute("atr", atributo);
n.setTextContent(nombre);
root.appendChild(n);
doc.appendChild(root);
var t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
var out = new StringWriter();
t.transform(new DOMSource(doc), new StreamResult(out));salida<root> <nombre atr="dijo "hola"">Gómez & Hijos <S.A.></nombre> </root> de vuelta: [Gómez & Hijos <S.A.>] atr=[dijo "hola"]
El &, los < > y las comillas se escapan solos. Al volver a leerlo se recupera exactamente lo que se escribió, y eso es lo que hay que exigir a cualquier forma de generar XML.
Entrada publicada en 2011 y revisada en octubre de 2026. Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio; las salidas están copiadas de esa ejecución.