Insert new element to an XML file using SAX Filter

10,824

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");
    }
    ...
}
Share:
10,824
Kenan Hadad
Author by

Kenan Hadad

Updated on June 04, 2022

Comments

  • Kenan Hadad
    Kenan Hadad about 2 years

    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?