Insert new element to an XML file using SAX Filter

filter, java, sax, xml

Solution

Your `XMLFilter` should delegate to another `ContentHandler` that serializes the document based on the sax events.

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(...));

Your callback should delegate to the `super` implementation, which forwards the events to the serializing `ContentHandler`.

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

In your `endElement` callback you can check if your are at the final closing tag and add additional sax events.

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");
    }
    ...
}

Problem

I have an XMl file that looks like: ``` <?xml version="1.0" encoding="UTF-8"?> <game > <moves> <turn>2</turn> <piece nr="1" /> <turn>4</turn> <piece nr="1" /> </moves> </game> ``` I am writing a Java program that takes the XML file as input then parses it with SAX and SAX filter and computes: - the sum of the content of turn element (here=6) - the number of piece elements (here=2) Then I want to use a SAX filter in order to generate an output XML file that are the same as the input one but with an additional element like: ``` <s:statistics> <s:turn-total>6</s:turn-total> <s:piece-count>2</s:piece-count> </s:statistics> ``` The prefix `s` is a reference to a namespace. My program so far is: ``` 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); } } } ``` What should I do next?

Original source