Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing an XML stream with no root element

I need to parse a continuous stream of well-formed XML elements, to which I am only given an already constructed java.io.Reader object. These elements are not enclosed in a root element, nor are they prepended with an XML header like <?xml version="1.0"?>", but are otherwise valid XML.

Using the Java org.xml.sax.XMLReader class does not work, because the XML Reader expects to parse well-formed XML, starting with an enclosing root element. So, it just reads the first element in the stream, which it perceives as the root, and fails in the next one, with the typical

org.xml.sax.SAXParseException: The markup in the document following the root element must be well-formed.

For files that do not contain a root element, but where such element does exist or can be defined (and is called, say, MyRootElement), one can do something like the following:

        Strint path = <the full path to the file>;

        XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();

        StringBuilder buffer = new StringBuilder();

        buffer.append("<?xml version=\"1.0\"?>\n");
        buffer.append("<!DOCTYPE MyRootElement ");
        buffer.append("[<!ENTITY data SYSTEM \"file:///");
        buffer.append(path);
        buffer.append("\">]>\n");
        buffer.append("<MyRootElement xmlns:...>\n");
        buffer.append("&data;\n");
        buffer.append("</MyRootElement>\n");

        InputSource source = new InputSource(new StringReader(buffer.toString()));

        xmlReader.parse(source);

I have tested the above by saving part of the java.io.Reader output to a file and it works. However, this approach is not applicable in my case and such extra information (XML header, root element) cannot be inserted, since the java.io.Reader object passed to my code is already constructed.

Essentially, I am looking for "fragmented XML parsing". So, my question is, can it be done, using standard Java APIs (including the org.sax.xml.* and java.xml.* packages)?

like image 413
PNS Avatar asked Jul 10 '11 11:07

PNS


People also ask

Does XML need a root element?

An XML document must have a single root element, which contains all other XML elements in the document.

Can XML have 2 root elements?

While a properly formed XML file can only have a single root element, an XSD or DTD file can contain multiple roots. If one of the roots matches that in the XML source file, that root element is used, otherwise you need to select one to use.

What is root tag in XML?

Each XML document has exactly one single root element. It encloses all the other elements and is, therefore, the sole parent element to all the other elements. ROOT elements are also called document elements. In HTML, the root element is the <html> element.


1 Answers

SequenceInputStream comes to the rescue:

    SAXParserFactory saxFactory = SAXParserFactory.newInstance();
    SAXParser parser = saxFactory.newSAXParser();

    parser.parse(
        new SequenceInputStream(
            Collections.enumeration(Arrays.asList(
            new InputStream[] {
                new ByteArrayInputStream("<dummy>".getBytes()),
                new FileInputStream(file),//bogus xml
                new ByteArrayInputStream("</dummy>".getBytes()),
            }))
        ), 
        new DefaultHandler()
    );
like image 129
user656449 Avatar answered Sep 19 '22 12:09

user656449