iosjdjoisdfijodjoi893
iosjdjoisdfijodjoi893

Reputation: 199

How can I parse the second XML tag?

I have an XML file online resembling this:

<example>
    <date>2012-10-13</date>
    <bob>What I already know how to get</bob>
</example>
<example>
    <date>2012-10-14</date>
    <bob>What I want as well as the above</bob>
</example>

Here's what I'm using to get the data in the "What I already know how to get" tag:

/**
 * Gets be called on opening tags like: <tag> Can provide attribute(s), when
 * xml was like: <tag attribute="attributeValue">
 */
@Override
public void startElement(String namespaceURI, String localName,
        String qName, Attributes atts) throws SAXException {
    if (localName.equals("example")) {
        this.in_example = true;
    } else if (localName.equals("bob")) {
        this.in_bob = true;
    }
}

/**
 * Gets be called on closing tags like: </tag>
 */
@Override
public void endElement(String namespaceURI, String localName, String qName)
        throws SAXException {
    if (localName.equals("example")) {
        this.in_example = false;
    } else if (localName.equals("bob")) {
        this.in_bob = false;
    }
}

/**
 * Gets be called on the following structure: <tag>characters</tag>
 */
@Override
public void characters(char ch[], int start, int length) {
    if (this.in_bob) {
                    // A custom DataParser
        myDataParser.setExtractedString(new String(ch, start, length));
    }
}

Ok, so here's the question... how can I get "What I want as well as the above", even though it's enclosed in similar tags to "What I already know how to get"?

Thanks in advance :)

N.B. The XML document like a forecast, so the date and the content of the other tags will always be changing.

Upvotes: 0

Views: 128

Answers (3)

Don Roby
Don Roby

Reputation: 41127

As Michael Kay noted, the document as shown is not valid XML.

Since you seem to have been able to parse and get the first value, I assume it's actually just part of a larger document.

If you want to collect data from more elements, you'll need to collect into a structure like a list rather than just a string, and properly control when you create a new entry in that list.

But the characters method doesn't work with the parser in quite the way you seem to think. It can be called multiple times by the parser for the content within a single tag. Instead of expecting to get it all at once, you need to collect data into a buffer and only expect it to be complete when endElement is called.

For collecting only the "bob" data into a list of strings, the following will do:

public class ExampleHandler extends DefaultHandler {

    private List<String> results = new ArrayList<String>();
    private StringBuilder builder = new StringBuilder();

    @Override
    public void startElement(String namespaceURI, String localName,
                             String qName, Attributes atts) throws SAXException {
        if (localName.equals("bob")) {
            builder.setLength(0);
        }
    }

    @Override
    public void endElement(String namespaceURI, String localName, String qName)
            throws SAXException {
        if (localName.equals("bob")) {
            results.add(builder.toString());
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) {
        builder.append(ch, start, length);
    }

    public List<String> getResults() {
        return results;
    }
}

If you want to collect the other data as well, it will of course be more complex, and you'll collect into something other than a list of strings, but this should give the basic idea.

Upvotes: 0

Michael Kay
Michael Kay

Reputation: 163282

If your file contains two <example> elements at the top level then it is not a well-formed XML document, so an XML parser will always give you a failure when you try to parse it.

It is however a well-formed XML external entity, so you can parse it by including it into a well-formed XML document using an entity reference.

Upvotes: 1

mercutio
mercutio

Reputation: 1066

You can add the answers to a List of Strings.

Modify the last function as such:

List<String> results = new ArrayList<String>();

/**
 * Gets be called on the following structure: <tag>characters</tag>
 */
@Override
public void characters(char ch[], int start, int length) {
    if (this.in_bob) {
                    // A custom DataParser
        results.add(new String(ch, start, length));
    }
}

After you finished walking through the xml, just parse the collected Strings.

Upvotes: 0

Related Questions