usar studio programacion móviles manejo desarrollo curso crear como archivos aplicaciones java xml filter sax

java - studio - Inserte un nuevo elemento en un archivo XML usando SAX Filter



manejo de archivos xml en java (3)

Corrígeme si estoy equivocado, pero creo que XMLReader y XMLFilter realmente no deben cambiar un documento. Puedo proporcionar un enfoque diferente que con usted puede cambiar el contenido de su documento también:

public class ExtXMLConfig { private JAXBContext context; private Marshaller m; private Unmarshaller um; private Schema schema = null; /** * Creates an ExtXMLConfig-object, which uses rootClass as object to parse * and save XML-files. * * @param rootClass * the class use create/parse xml-files from * @throws JAXBException */ public ExtXMLConfig(Class<?> rootClass) throws JAXBException { context = JAXBContext.newInstance(rootClass); init(); } /** * Creates an ExtXMLConfig, which uses a classPath like javax.xml.bin to use * all classes in that path to parse and write xml-files * * @param classPath * the class path containing all needed java-objects * @throws JAXBException */ public ExtXMLConfig(String classPath) throws JAXBException { context = JAXBContext.newInstance(classPath); init(); } /** * Parses a xml-file into a JavaObject. * * @param file * path to the xml-file * @return a java-Object */ public Object load(String file) { return load(new File(file)); } /** * Parses a xml-file into a JavaObject. * * @param xml * File-object representing the xml-file * @return a java-Object */ public Object load(File xml) { um.setSchema(schema); if (xml.exists() && xml.isFile()) { try { return um.unmarshal(xml); } catch (JAXBException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { System.out.println("Failed to open file: " + xml.getAbsolutePath()); } return null; } /** * Saves a object into a xml-file. * * @param xml * the object to save * @param file * path to the file to save to */ public void save(Object xml, String file) { save(xml, new File(file)); } /** * Saves a object into a xml-file. * * @param xml * the object to save * @param file * File-object representing the file to save to */ public void save(Object xml, File file) { if (xml != null) { m.setSchema(schema); if (!file.isDirectory()) { try { if (!file.exists()) { file.createNewFile(); } m.marshal(xml, file); } catch (JAXBException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /** * Returns a formatted string representation of a xml-file given as a * java-Object. * * @param xml * the java-object to parse the xml from. * @return a formatted string representation of the given object */ public String toString(Object xml) { StringWriter out = new StringWriter(); try { m.setSchema(schema); m.marshal(xml, out); return out.toString(); } catch (JAXBException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } private void init() throws JAXBException { m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); um = context.createUnmarshaller(); }

Usando esta clase para analizar tus archivos xml, solo necesitarías una clase como esta:

@XmlRootElement // used to parse this class as xml-Root public class Game { private Move moves; public Game() {}; public void setMove(Move moves) { this.moves = moves; } public Moves getMoves() { return this.moves; } }

con Move siendo una instancia de otra clase que tiene los campos que necesita y también tiene una anotación para XmlRootElement.

Espero que esto ayude.

Tengo un archivo XMl que se ve así:

<?xml version="1.0" encoding="UTF-8"?> <game > <moves> <turn>2</turn> <piece nr="1" /> <turn>4</turn> <piece nr="1" /> </moves> </game>

Estoy escribiendo un programa Java que toma el archivo XML como entrada y luego lo analiza con SAX y filtro SAX y calcula:

  • la suma del contenido del elemento de giro (aquí = 6)
  • la cantidad de elementos pieza (aquí = 2)

Luego quiero usar un filtro SAX para generar un archivo XML de salida que sea el mismo que el de entrada, pero con un elemento adicional como:

<s:statistics> <s:turn-total>6</s:turn-total> <s:piece-count>2</s:piece-count> </s:statistics>

El prefijo s es una referencia a un espacio de nombres .

Mi programa hasta ahora es:

public class test{ public static void main(String[] args) throws Exception { if (args.length != 2) { System.err.println("error "); System.exit(1); } String xmlInput = args[0]; String filteredXML = args[1]; test test1 = new test(); test1.sax(xmlInput, filteredXML); } private void sax(String gameXML, String filteredGameXML)throws Exception{ FileInputStream fis = new FileInputStream( gameXML); InputSource is = new InputSource(fis); XMLReader xr = XMLReaderFactory.createXMLReader(); XMLFilter xf = new MyFilter(); xf.setParent(xr); xr = xf; xr.parse(is); xr.setFeature("http://xml.org/sax/features/namespaces", true); DefaultHandler handler = new DefaultHandler(); xr.setContentHandler(handler); } private class MyFilter extends XMLFilterImpl{ StringBuffer buffer; int temp=0; int sum=0; String ff; int numof=0; private MyFilter() {} @Override public void startDocument() throws SAXException { System.out.println( "START DOCUMENT" ); numof=0; } public void startElement(String namespaceURI, String localName, String name, Attributes attributes) throws SAXException{ if(localName.equals("turn")){ buffer=new StringBuffer(); } if("piece".equals(name)){ numof++; } } public void characters(char[] ch, int start, int length) throws SAXException { String s=new String(ch, start, length); if(buffer!=null){ buffer.append(s); } } public void endElement(String uri, String localName, String name)throws SAXException { if(buffer!=null ){ ff=buffer.toString(); temp=Integer.valueOf(ff); sum=sum+temp; } buffer=null; } public void endDocument() throws SAXException { System.out.println( "END DOCUMENT" ); System.out.println("sum of turn: "+ sum); System.out.println("sum of piece: "+ numof); } } }

¿Qué debería hacer después?


Utilizando la respuesta de @Jorn Horstmann (http://.com/users/139595/jorn-horstmann) desde arriba, puede agregar fácilmente los elementos faltantes. Pero para escribir los resultados en un archivo XML, debe usar el TransformerHandler.

Simplemente cree un ContentHandler muy básico y úselo en lugar del DefaultHandler. En ContentHandler puede implementar todas las funciones básicas (startDocument, startElement, etc.) y agregar cada elemento a un nuevo Transformer. Por ejemplo, en su función startDocument:

Transformer t = hd.getTransformer(); t.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); t.setOutputProperty(OutputKeys.METHOD, "xml"); t.setOutputProperty(OutputKeys.INDENT, "yes"); hd.startDocument();

Y luego (en cada otra función) agregue esto: por ejemplo, para startElement:

hd.startElement(uri,localName,name,attributes);

Finalmente puede escribir todo esto en un archivo en el método endDocument.


Su XMLFilter debe delegar en otro ContentHandler que ContentHandler el documento basado en los eventos sax.

SAXTransformerFactory factory = (SAXTransformerFactory)TransformerFactory.newInstance(); TransformerHandler serializer = factory.newTransformerHandler(); Result result = new StreamResult(...); serializer.setResult(result); XMLFilterImpl filter = new MyFilter(); filter.setContentHandler(serializer); XMLReader xmlreader = XMLReaderFactory.createXMLReader(); xmlreader.setFeature("http://xml.org/sax/features/namespaces", true); xmlreader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); xmlreader.setContentHandler(filter); xmlreader.parse(new InputSource(...));

Su devolución de llamada debe delegar en la implementación super , que reenvía los eventos al serializador ContentHandler .

public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { super.startElement(namespaceURI, localName, qName, atts); ... }

En su endElement llamada endElement puede verificar si se encuentra en la etiqueta de cierre final y agregar eventos sax adicionales.

public void endElement(String namespaceURI, String localName, String qName) throws SAXException { super.endElement(namespaceURI, localName, qName); if ("game".equals(localName)) { super.startElement("", "statistics", "statistics", new AttributesImpl()); char[] chars = String.valueOf(num).toCharArray(); super.characters(chars, 0, chars.length); super.endElement("", "statistics", "statistics"); } ... }