B3 · SAX y acumulación de texto
Bloques B07–B08. Los fragmentos omiten los import y el manejo de excepciones. Salvo que se diga otra cosa, se usa SAXParserFactory.newInstance() sin activar espacios de nombres. Los XML se muestran indentados para leerlos mejor, pero el fichero no tiene espacios ni saltos de línea entre etiquetas salvo que el enunciado diga que la indentación es real.
Modelo push
¿Qué describe mejor el funcionamiento de SAX?
- La aplicación pide el siguiente evento con
next().Eso es StAX (modelo pull).
- El parser recorre el documento una vez y llama a los métodos del manejador cuando encuentra cada parte (modelo push).
Correcta (B07.1).
- Construye un árbol en memoria y después lo recorre.
Eso es DOM.
- Permite volver atrás para releer un elemento anterior.
SAX no retiene el documento; hay que guardar estado propio o releer.
- Convierte el XML en objetos Java anotados.
Eso es JAXB.
- Solo funciona con documentos pequeños.
Precisamente es adecuado para documentos grandes.
Repasar: B07.1, B02.1.
Arrancar el análisis
¿Qué secuencia lanza correctamente el análisis con un manejador propio MiHandler extends DefaultHandler?
-
new SAXParser().parse(new File("a.xml"), new MiHandler());SAXParseres abstracta: se obtiene de la factoría. -
SAXParserFactory.newInstance().parse(new File("a.xml"), new MiHandler());La factoría no parsea.
-
SAXParserFactory.newInstance().newSAXParser().parse(new File("a.xml"), new MiHandler());Correcta (B07.1).
-
DocumentBuilderFactory.newInstance().newSAXParser().parse(...)Esa factoría es la de DOM.
-
new MiHandler().parse(new File("a.xml"));El manejador recibe eventos; no analiza.
-
SAXParserFactory.newInstance().newSAXParser().parse(new MiHandler(), new File("a.xml"));Primero va el origen y después el manejador.
Repasar: B07.1.
Orden de los callbacks
Para este XML, sin espacios entre etiquetas, ¿en qué orden se llaman los callbacks?
<a x="1"> <b>t</b></a>-
startDocument,startElement a,characters "1",startElement b,characters "t",endElement b,endElement a,endDocumentLos atributos llegan en
startElement(parámetroAttributes), no encharacters. -
startDocument,startElement a,startElement b,characters "t",endElement b,endElement a,endDocumentCorrecta: orden del documento, y el atributo va dentro de
startElement a. -
startDocument,startElement a,endElement a,startElement b,characters "t",endElement b,endDocumentbestá dentro dea:ase cierra al final. -
startElement a,startElement b,characters "t",endElement b,endElement aFaltan
startDocumentyendDocument. -
startDocument,startElement b,startElement a, …Se respeta el orden del documento.
-
startDocument,startElement a,startElement x, …Un atributo no genera
startElement.
Repasar: B07.2, B07.3.
Tramo válido de characters
El parser llama a este characters con ch = {'x','x','L','u','i','s','y'}, start = 2 y length = 4, y el acumulador estaba vacío. ¿Qué imprime?
private final StringBuilder texto = new StringBuilder();
@Overridepublic void characters(char[] ch, int start, int length) { texto.append(ch, start, length); System.out.println(texto);}-
xxLuisyToma el array completo ignorando
startylength. -
LuisCorrecta: índices 2 a 5.
-
LuInterpreta
lengthcomo índice final. -
xxLuEmpieza en 0 y toma 4.
-
uisyEmpieza un carácter tarde.
-
xxLuisToma
start + lengthcaracteres desde el 0.
Repasar: B08.1.
Acumulador sustituido
El texto de <nombre>Luis</nombre> llega en dos llamadas: "Lu" y "is". ¿Qué imprime este manejador en endElement?
private String texto = "";
@Overridepublic void characters(char[] ch, int start, int length) { texto = new String(ch, start, length);}@Overridepublic void endElement(String uri, String local, String qName) { if ("nombre".equals(qName)) System.out.println(texto);}-
LuisCada llamada sustituye el valor anterior.
-
isCorrecta: hay que acumular con
StringBuilder.append(ch, start, length). -
LuLa segunda llamada sobrescribe la primera.
-
isLuNo se acumula.
- Una cadena vacía.
La última llamada deja
is. - Lanza
SAXExceptionpor texto fragmentado.La fragmentación es un comportamiento permitido.
Repasar: B08.1, B15.2.3.
Dónde procesar el texto
Con el patrón de acumulación del temario, ¿en qué callback debe interpretarse el texto completo de un campo simple?
- En
startElement, porque ahí empieza el campo.Todavía no ha llegado el texto.
- En cada llamada a
characters.Puede llegar solo una parte del texto.
- En
endElementdel campo, tras haber acumulado todos los tramos.Correcta (B08.2).
- En
startDocument.Es el inicio del documento.
- En el constructor del manejador.
El constructor se ejecuta antes del análisis.
- En
endDocument, y solo ahí.Al final se habrían mezclado todos los campos.
Repasar: B08.2.
Contar elementos vacíos
¿Qué imprime el contador al terminar con este XML?
<l> <i/> <i>t</i> <i/></l>int n = 0;
@Overridepublic void startElement(String uri, String local, String qName, Attributes atts) { if ("i".equals(qName)) n++;}@Overridepublic void endDocument() { System.out.println(n);}- 1
Cuenta solo el que tiene texto; los vacíos también tienen inicio.
- 3
Correcta:
<i/>producestartElementyendElement. - 4
Cuenta también
l, pero la condición lo excluye. - 6
Cuenta inicios y finales; solo se cuenta en
startElement. - 2
Olvida uno de los vacíos.
- 0
qNamesí trae el nombre con la factoría por defecto.
Repasar: B07.3.
localName sin espacios de nombres
Con SAXParserFactory.newInstance() por defecto (sin setNamespaceAware(true)), ¿qué reciben localName y qName en startElement para <student>?
- Los dos valen
student.No siempre: depende de la configuración de namespaces.
-
qNamevalestudentylocalNamepuede llegar vacío.Correcta: sin namespaces, el nombre fiable es
qName. -
localNamevalestudentyqNameesnull.Es al revés.
- Ambos son
null.qNamesí trae el nombre. -
uricontienestudent.uries el espacio de nombres. -
qNamevale<student>con los signos.Solo el nombre, sin
<ni>.
Repasar: B07.2.
Atributo ausente en SAX
¿Qué imprime este manejador para <student rollno="393"/>?
@Overridepublic void startElement(String uri, String local, String qName, Attributes attributes) { System.out.println(attributes.getValue("rollno") + " " + attributes.getValue("curso"));}Las opciones indican qué devuelve cada una de las dos llamadas.
-
"393"y""En SAX, un atributo ausente devuelve
null(en DOMgetAttributedevuelve""). -
"393"ynullCorrecta (B07.2).
-
393(entero) y0Los valores son
String. -
nullynull, porque los atributos llegan encharacters.Llegan en el parámetro
Attributes. -
"393"y lanzaSAXException.No es un error pedir un atributo ausente.
-
"rollno=393"ynullDevuelve solo el valor.
Repasar: B07.2, B15.1.
Manejador que reinicia en cada etiqueta
El manejador reinicia el acumulador en cada startElement, acumula en characters y en cada endElement imprime qName + "=" + texto y vuelve a vaciarlo. ¿Qué imprime para este XML? Tiene contenido mixto, así que se escribe en una sola línea.
<nombre>Lu<parte>is</parte></nombre>-
nombre=LuisEl reinicio al abrir
partepierde elLudel padre. -
parte=isynombre=Luisnombreno conserva su texto porque se vació. -
parte=isynombre=(vacío)Correcta: este estado simple sirve para hojas, no para contenido mixto.
-
parte=Luisynombre=El acumulador se reinició al empezar
parte. -
nombre=Luyparte=ispartese cierra antes quenombre. - Lanza
SAXExceptionpor contenido mixto.El contenido mixto es XML válido.
Repasar: B08.3, B14.2.
Espacios de indentación
Este manejador se ejecuta sobre este XML, cuya indentación es real (los saltos de línea y espacios están en el fichero). ¿Qué se observa en la salida?
<a> <b>x</b></a>@Overridepublic void characters(char[] ch, int start, int length) { System.out.println("[" + new String(ch, start, length) + "]");}- Solo aparecen los textos de las hojas.
Los espacios de indentación también son texto.
- También aparecen fragmentos formados solo por saltos y espacios.
Correcta: hay que filtrar o aplicar
trim()con criterio. - El parser lanza un error por los espacios.
La indentación es válida.
- Los espacios llegan a
startElement.Llegan a
characters. - Se imprime el marcado de las etiquetas.
charactersno recibe etiquetas. - Nada:
characterssolo se llama en elementos con atributos.Se llama con cualquier texto.
Repasar: B07.3.
Analizar sin lógica propia
¿Qué ocurre con parser.parse(new File("a.xml"), new DefaultHandler()) si el XML está bien formado?
- No compila:
DefaultHandleres abstracta.Es una clase concreta con métodos vacíos.
- Lo analiza sin errores, pero no extrae ni muestra nada.
Correcta: los callbacks heredados no hacen nada.
- Imprime todo el XML por consola.
No tiene lógica de impresión.
- Devuelve un
Documentcon el árbol.parsede SAX devuelvevoid. - Guarda los datos en una lista interna.
SAX no guarda datos por la aplicación.
- Lanza
SAXExceptionporque no hay callbacks sobrescritos.Los callbacks son opcionales.
Repasar: B07.1.
Datos de un registro
Para saber a qué student pertenece cada firstname, ¿qué debe hacer el manejador?
- Llamar a
getParentNode()dentro decharacters.SAX no ofrece un árbol navegable.
- Mantener estado propio: por ejemplo, guardar el
rollnoactual enstartElementdestudent.Correcta (B07.3).
- Pedir al parser que vuelva al
studentanterior.SAX no retrocede.
- Leer el atributo en
endElement.endElementno recibe atributos. - Usar
getElementsByTagName("student").Es un método de DOM.
- Nada: SAX asocia los datos automáticamente.
La aplicación es responsable del estado.
Repasar: B07.3.
InputSource y setEncoding
El archivo f está en UTF-8 y contiene acentos. ¿Qué ocurre?
Reader r = new InputStreamReader(new FileInputStream(f), "ISO-8859-1");InputSource is = new InputSource(r);is.setEncoding("UTF-8");parser.parse(is, handler);-
setEncodingcorrige la decodificación y los acentos se leen bien.Con un
Reader, los bytes ya se decodificaron como ISO-8859-1. - Los caracteres ya llegan decodificados por el
Reader;setEncodingno los reinterpreta y los acentos pueden salir mal.Correcta (B08.4).
- El parser lanza un error por incoherencia de codificaciones.
No compara ambas.
-
InputSourceno admite unReader.Sí lo admite.
- El parser vuelve a leer el archivo en bytes.
Trabaja con el
Readerrecibido. - Da igual: SAX siempre usa UTF-8.
Con bytes, el parser interpreta la declaración; con un
Reader, usa los caracteres que recibe.
Repasar: B08.4.
Mayúsculas en XML
El ejemplo docente compara nombres con equalsIgnoreCase. ¿Qué afirmación es correcta?
- Es obligatorio, porque XML no distingue mayúsculas.
XML sí distingue mayúsculas:
<Libro>y<libro>son distintos. - XML distingue mayúsculas; comparar sin distinguirlas es una decisión de la aplicación, no una regla del formato.
Correcta (B08.3, B01.1).
- SAX convierte todos los nombres a minúsculas.
Entrega los nombres tal como están.
- Con
equalsel parser lanzaría una excepción.La comparación la hace la aplicación.
-
<Libro>puede cerrarse con</libro>.Estaría mal formado.
-
equalsIgnoreCasees necesario para leer atributos.Los atributos se leen con
getValue.
Repasar: B08.3, B01.1.
Progreso del cuestionario
0 / 0 preguntas respondidas (0%)
0 correctas
¡Cuestionario completado!
0%
0 / 0 correctas
Tiempo: