Skipping nodes with sax
Asked Answered
M

3

4

Is it possible to skip nodes when parsing and how, does this skippedEntity have anything to do with it?

Consider this XML :

<?xml version="1.0"?>

<nutrition>

<daily-values>
    <total-fat units="g">65</total-fat>
    <saturated-fat units="g">20</saturated-fat>
    <cholesterol units="mg">300</cholesterol>
    <sodium units="mg">2400</sodium>
    <carb units="g">300</carb>
    <fiber units="g">25</fiber>
    <protein units="g">50</protein>
</daily-values>

</nutrition>

I want to skip "sodium" element

Midway answered 28/7, 2010 at 20:32 Comment(0)
N
8

You could do something like the following:

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.XMLReader;

public class Demo {

    public static void main(String[] args) throws Exception {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();
        XMLReader xr = sp.getXMLReader();
        xr.setContentHandler(new MyContentHandler(xr));
        xr.parse("input.xml");
    }
}

MyContentHandler

This class is responsible for processing your XML document. When you hit a node you want to ignore you can swap in the IgnoringContentHandler which will swallow all events for that node.

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class MyContentHandler extends DefaultHandler {

    private XMLReader xmlReader;

    public MyContentHandler(XMLReader xmlReader) {
        this.xmlReader = xmlReader;
    }

    public void startElement(String uri, String localName, String qName,
            Attributes atts) throws SAXException {
        if ("sodium".equals(qName)) {
            xmlReader.setContentHandler(new IgnoringContentHandler(xmlReader,
                    this));
        } else {
            System.out.println("START " + qName);
        }
    }

    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        System.out.println("END " + qName);
    }

    public void characters(char[] ch, int start, int length)
            throws SAXException {
        System.out.println(new String(ch, start, length));
    }

}

IgnoringContentHandler

When the IgnoringContentHandler is done swallowing events it passes control back to your main ContentHandler.

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class IgnoringContentHandler extends DefaultHandler {

    private int depth = 1;
    private XMLReader xmlReader;
    private ContentHandler contentHandler;

    public IgnoringContentHandler(XMLReader xmlReader, ContentHandler contentHandler) {
        this.contentHandler = contentHandler;
        this.xmlReader = xmlReader;
    }

    public void startElement(String uri, String localName, String qName,
            Attributes atts) throws SAXException {
        depth++;
    }

    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        depth--;
        if(0 == depth) {
           xmlReader.setContentHandler(contentHandler);
        }
    }

}
Neibart answered 29/7, 2010 at 20:10 Comment(2)
@vtd-xml-author - I have switched the code to extend DefaultHandler rather than implement ContentHandler directly, this should make the code easier to understand. Chaining content handlers is a very powerful mechanism in standard SAX parsing.Neibart
Since the default behavior for all these methods is "do nothing", I'm having a hard time seeing what this accomplishes other than setting one content handler that in turn sets it back. MyContentHandler was already going to not do anything more than you prepared it toErythema
A
3

Please edit your post to include a sample XML and a description of what you mean by "skip nodes".

Since your parser gets control on each event, you can choose to do nothing based on any criteria you desire. If you want to skip an entire subtree, you have to set a global flag when you encounter the subtree's start element and clear the flag at the end element; then use the flag to control processing of the contained nodes.

Ashcroft answered 28/7, 2010 at 20:50 Comment(2)
I added xml, I want to skip "sodium" elementMidway
OK, what do you mean by "skip"? In a SAX parser you're in control... you get handed parsing events and can do whatever you want. You'll get a start-element event for every tag, and when the tag name is "sodium" you can write logic to just return, ignoring the data. Edit your post and show what you have tried so far in Java.Ashcroft
L
1

Unfortunately I don't have privileges to comment on other answers. I just wanted to correct "Wayne"s incorrect assertion that Blaise's answer "doesn't work". I have tried this code and it does indeed output all the values from the example data except that for Sodium - which I think is exactly what the OP was seeking.

Lavadalavage answered 4/12, 2011 at 14:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.