tag attribute java xml xml-parsing

attribute - Análisis del archivo XML que contiene entidades HTML en Java sin cambiar el XML



title css (6)

Problema - 1: tengo que analizar un montón de archivos XML en Java que a veces - y de forma no válida - contienen entidades HTML como —

XML tiene solo cinco entidades predefinidas . El — ,   No está entre ellos. Funciona solo cuando se usa en HTML simple o en JSP heredado. Entonces, SAX no ayudará. Se puede hacer usando StaX que tiene un API de alto nivel basado en iteradores . (Recogido desde este link )

Problema - 2: encontré que puedo anular la entidad de resolución en org.xml.sax.helpers.DefaultHandler, pero ¿cómo uso esto con la API de nivel superior ?

Streaming API para XML, llamada StaX , es una API para reading and writing XML Documents .

StaX es un modelo Pull-Parsing. La aplicación puede tomar el control sobre el análisis de los documentos XML al extraer (tomar) los eventos del analizador.

La API básica de StaX se divide en two categories y se enumeran a continuación. Son

  • API basada en el cursor: es low-level API . La API basada en el cursor permite que la aplicación procese XML como una secuencia de tokens aka eventos

  • API basada en iterador: la API basada en iterador de higher-level permite a la aplicación procesar XML como una serie de objetos de evento, cada uno de los cuales comunica una parte de la estructura XML a la aplicación.

STaX API has support for the notion of not replacing character entity references , a través de la propiedad IS_REPLACING_ENTITY_REFERENCES :

Requiere que el analizador reemplace las referencias de entidades internas con su texto de reemplazo y las reporte como caracteres

Esto se puede establecer en un XmlInputFactory , que a su vez se utiliza para construir un XmlEventReader o XmlStreamReader .

Sin embargo, la API es cuidadosa al decir que esta propiedad solo pretende forzar a la implementación a realizar el reemplazo, en lugar de forzarla a no reemplazarla.

Puedes intentarlo. Espero que resuelva tu problema. Para su caso,

Main.java

import java.io.FileInputStream; import java.io.FileNotFoundException; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.EntityReference; import javax.xml.stream.events.XMLEvent; public class Main { public static void main(String[] args) { XMLInputFactory inputFactory = XMLInputFactory.newInstance(); inputFactory.setProperty( XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false); XMLEventReader reader; try { reader = inputFactory .createXMLEventReader(new FileInputStream("F://test.xml")); while (reader.hasNext()) { XMLEvent event = reader.nextEvent(); if (event.isEntityReference()) { EntityReference ref = (EntityReference) event; System.out.println("Entity Reference: " + ref.getName()); } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (XMLStreamException e) { e.printStackTrace(); } } }

test.xml:

<?xml version="1.0" encoding="UTF-8"?> <foo> <bar>Some&nbsp;text &mdash; invalid!</bar> </foo>

Salida:

Referencia de la entidad: nbsp

Referencia de la entidad: mdash

El crédito es para @skaffman .

Enlace relacionado:

  1. http://www.journaldev.com/1191/how-to-read-xml-file-in-java-using-java-stax-api
  2. http://www.journaldev.com/1226/java-stax-cursor-based-api-read-xml-example
  3. http://www.vogella.com/tutorials/JavaXML/article.html
  4. ¿Existe una API XML de Java que pueda analizar un documento sin resolver entidades de caracteres?

ACTUALIZAR:

Problema - 3: ¿Hay una manera de usar StaX para "filtrar" las entidades (reemplazándolas con otra cosa, por ejemplo) y aún así producir un documento al final del proceso?

Para crear un nuevo documento utilizando la API StAX, se requiere crear un XMLStreamWriter que proporcione métodos para producir etiquetas de apertura y cierre, atributos y contenido de caracteres XML.

Hay 5 métodos de XMLStreamWriter para el documento.

  1. xmlsw.writeStartDocument(); - Inicializa un documento vacío al que se pueden agregar elementos.
  2. xmlsw.writeStartElement(String s) crea un nuevo elemento llamado s
  3. xmlsw.writeAttribute(String name, String value) : agrega el nombre de atributo con el valor correspondiente al último elemento producido por una llamada a writeStartElement. Es posible agregar atributos siempre que no se haya realizado ninguna llamada a writeElementStart, writeCharacters o writeEndElement.
  4. xmlsw.writeEndElement - cierra el último elemento iniciado
  5. xmlsw.writeCharacters(String s) : crea un nuevo nodo de texto con contenido s como contenido del último elemento iniciado.

Un ejemplo de ejemplo se adjunta con él:

StAXExpand.java

import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import java.util.Arrays; public class StAXExpand { static XMLStreamWriter xmlsw = null; public static void main(String[] argv) { try { xmlsw = XMLOutputFactory.newInstance() .createXMLStreamWriter(System.out); CompactTokenizer tok = new CompactTokenizer( new FileReader(argv[0])); String rootName = "dummyRoot"; // ignore everything preceding the word before the first "[" while(!tok.nextToken().equals("[")){ rootName=tok.getToken(); } // start creating new document xmlsw.writeStartDocument(); ignorableSpacing(0); xmlsw.writeStartElement(rootName); expand(tok,3); ignorableSpacing(0); xmlsw.writeEndDocument(); xmlsw.flush(); xmlsw.close(); } catch (XMLStreamException e){ System.out.println(e.getMessage()); } catch (IOException ex) { System.out.println("IOException"+ex); ex.printStackTrace(); } } public static void expand(CompactTokenizer tok, int indent) throws IOException,XMLStreamException { tok.skip("["); while(tok.getToken().equals("@")) {// add attributes String attName = tok.nextToken(); tok.nextToken(); xmlsw.writeAttribute(attName,tok.skip("[")); tok.nextToken(); tok.skip("]"); } boolean lastWasElement=true; // for controlling the output of newlines while(!tok.getToken().equals("]")){ // process content String s = tok.getToken().trim(); tok.nextToken(); if(tok.getToken().equals("[")){ if(lastWasElement)ignorableSpacing(indent); xmlsw.writeStartElement(s); expand(tok,indent+3); lastWasElement=true; } else { xmlsw.writeCharacters(s); lastWasElement=false; } } tok.skip("]"); if(lastWasElement)ignorableSpacing(indent-3); xmlsw.writeEndElement(); } private static char[] blanks = "/n".toCharArray(); private static void ignorableSpacing(int nb) throws XMLStreamException { if(nb>blanks.length){// extend the length of space array blanks = new char[nb+1]; blanks[0]=''/n''; Arrays.fill(blanks,1,blanks.length,'' ''); } xmlsw.writeCharacters(blanks, 0, nb+1); } }

CompactTokenizer.java

import java.io.Reader; import java.io.IOException; import java.io.StreamTokenizer; public class CompactTokenizer { private StreamTokenizer st; CompactTokenizer(Reader r){ st = new StreamTokenizer(r); st.resetSyntax(); // remove parsing of numbers... st.wordChars(''/u0000'',''/u00FF''); // everything is part of a word // except the following... st.ordinaryChar(''/n''); st.ordinaryChar(''[''); st.ordinaryChar('']''); st.ordinaryChar(''@''); } public String nextToken() throws IOException{ st.nextToken(); while(st.ttype==''/n''|| (st.ttype==StreamTokenizer.TT_WORD && st.sval.trim().length()==0)) st.nextToken(); return getToken(); } public String getToken(){ return (st.ttype == StreamTokenizer.TT_WORD) ? st.sval : (""+(char)st.ttype); } public String skip(String sym) throws IOException { if(getToken().equals(sym)) return nextToken(); else throw new IllegalArgumentException("skip: "+sym+" expected but"+ sym +" found "); } }

Para más, puedes seguir el tutorial.

  1. https://docs.oracle.com/javase/tutorial/jaxp/stax/example.html
  2. http://www.ibm.com/developerworks/library/x-tipstx2/index.html
  3. http://www.iro.umontreal.ca/~lapalme/ForestInsteadOfTheTrees/HTML/ch09s03.html
  4. http://staf.sourceforge.net/current/STAXDoc.pdf

Tengo que analizar un montón de archivos XML en Java que a veces, y de forma no válida, contienen entidades HTML como &mdash; , &gt; Etcétera. Entiendo que la forma correcta de lidiar con esto es agregar declaraciones de entidad adecuadas al archivo XML antes de analizar. Sin embargo, no puedo hacerlo ya que no tengo control sobre esos archivos XML.

¿Existe algún tipo de devolución de llamada que pueda anular y que se invoque cada vez que el analizador de Java XML se encuentre con una entidad de este tipo? No he podido encontrar uno en la API.

Me gustaría usar:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = dbf.newDocumentBuilder(); Document doc = parser.parse( stream );

Descubrí que puedo invalidar la resolveEntity de resolveEntity en org.xml.sax.helpers.DefaultHandler , pero ¿cómo uso esto con la API de nivel superior?

Aquí hay un ejemplo completo:

public class Main { public static void main( String [] args ) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = dbf.newDocumentBuilder(); Document doc = parser.parse( new FileInputStream( "test.xml" )); }

}

con test.xml:

<?xml version="1.0" encoding="UTF-8"?> <foo> <bar>Some&nbsp;text &mdash; invalid!</bar> </foo>

Produce:

[Fatal Error] :3:20: The entity "nbsp" was referenced, but not declared. Exception in thread "main" org.xml.sax.SAXParseException; lineNumber: 3; columnNumber: 20; The entity "nbsp" was referenced, but not declared.

Actualización: He estado hurgando en el código fuente de JDK con un depurador, y chico, qué cantidad de espaguetis. No tengo idea de qué diseño hay, o si hay uno. ¿Cuántas capas de una cebolla puede una capa una encima de la otra?

La clase clave parece ser com.sun.org.apache.xerces.internal.impl.XMLEntityManager , pero no puedo encontrar ningún código que me permita agregar cosas antes de que se use, o que intenta resolver entidades sin pasar por ellas. esa clase.


Hice ayer algo similar que necesito para agregar valor de XML descomprimido en transmisión a la base de datos.

//import I''m not sure if all are necessary :) import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.*; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; //I didnt checked this code now because i''m in work for sure its work maybe you will need to do little changes InputSource is = new InputSource(new FileInputStream("test.xml")); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(is); XPathFactory xpf = XPathFactory.newInstance(); XPath xpath = xpf.newXPath(); String words= xpath.evaluate("/foo/bar", doc.getDocumentElement()); ParsingHexToChar.parseToChar(words); // lib which i use common-lang3.jar //metod to parse public static String parseToChar( String words){ String decode= org.apache.commons.lang3.StringEscapeUtils.unescapeHtml4(words); return decode; }


Intenta esto usando el paquete org.apache.commons:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = dbf.newDocumentBuilder(); InputStream in = new FileInputStream(xmlfile); String unescapeHtml4 = IOUtils.toString(in); CharSequenceTranslator obj = new AggregateTranslator(new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()), new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE()) ); unescapeHtml4 = obj.translate(unescapeHtml4); StringReader readerInput= new StringReader(unescapeHtml4); InputSource is = new InputSource(readerInput); Document doc = parser.parse(is);


Otro enfoque, ya que no está utilizando un enfoque rígido OXM de todos modos. Es posible que desee probar con un analizador menos rígido como JSoup? Esto detendrá los problemas inmediatos con esquemas XML no válidos, etc., pero solo devolverá el problema a su código.


Solo para lanzar un enfoque diferente a una solución:

Puede envolver su flujo de entrada con una implementación de flujo que reemplaza a las entidades por algo legal.

Si bien este es un truco seguro, debería ser una solución rápida y fácil (o mejor dicho: solución).
Sin embargo, no es tan elegante y limpio como una solución interna de marco xml.


Yo usaría una biblioteca como Jsoup para este propósito. He probado lo siguiente a continuación y funciona. No sé si esto ayuda. Se puede encontrar aquí: http://jsoup.org/download

public static void main(String args[]){ String html = "<?xml version=/"1.0/" encoding=/"UTF-8/"?><foo>" + "<bar>Some&nbsp;text &mdash; invalid!</bar></foo>"; Document doc = Jsoup.parse(html, "", Parser.xmlParser()); for (Element e : doc.select("bar")) { System.out.println(e); } }

Resultado:

<bar> Some&nbsp;text — invalid! </bar>

La carga de un archivo se puede encontrar aquí:

http://jsoup.org/cookbook/input/load-document-from-file