Reading multiple XML documents from a socket in java

I am writing a client that needs to read several consecutive small XML documents through a socket. I can assume that the encoding is always UTF-8 and that there is an optional separation of spaces between documents. Documents should eventually go into DOM objects. What is the best way to do this?

The essence of the problem is that the parsers expect that there will be one document in the stream, and consider the rest of the unwanted information. I thought I could artificially finish the document by tracking the depth of the element and creating a new reader using the existing input stream. For example. sort of:

// Broken 
public void parseInputStream(InputStream inputStream) throws Exception
{
    XMLInputFactory factory = XMLInputFactory.newInstance();
    XMLOutputFactory xof = XMLOutputFactory.newInstance();
    XMLEventFactory eventFactory = XMLEventFactory.newInstance();        
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    Document doc = documentBuilder.newDocument();
    XMLEventWriter domWriter = xof.createXMLEventWriter(new DOMResult(doc));
    XMLStreamReader xmlStreamReader = factory.createXMLStreamReader(inputStream);
    XMLEventReader reader = factory.createXMLEventReader(xmlStreamReader);
    int depth = 0;

    while (reader.hasNext()) {
        XMLEvent evt = reader.nextEvent();
        domWriter.add(evt);

        switch (evt.getEventType()) {
        case XMLEvent.START_ELEMENT:
            depth++;
            break;

        case XMLEvent.END_ELEMENT:
            depth--;

            if (depth == 0) 
            {                       
                domWriter.add(eventFactory.createEndDocument());
                System.out.println(doc);
                reader.close();
                xmlStreamReader.close();

                xmlStreamReader = factory.createXMLStreamReader(inputStream);
                reader = factory.createXMLEventReader(xmlStreamReader);

                doc = documentBuilder.newDocument();
                domWriter = xof.createXMLEventWriter(new DOMResult(doc));    
                domWriter.add(eventFactory.createStartDocument());
            }
            break;                    
        }
    }
}

, <a> </a> <b> <c> </c> XMLStreamException. ?

: , .

+3
9
  • - ( ).
  • , ByteArrayOutputStream
  • ByteArrayInputStream
  • ByteArrayInputStream,
  • ..
+3

IIRC, XML , , .

. , NUL . , , .

+1

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

public class LogParser {

    private XMLInputFactory inputFactory = null;
    private XMLStreamReader xmlReader = null;
    InputStream is;
    private int depth;
    private QName rootElement;

    private static class XMLStream extends InputStream
    {
        InputStream delegate;
        StringReader startroot = new StringReader("<root>");
        StringReader endroot = new StringReader("</root>");

        XMLStream(InputStream delegate)
        {
            this.delegate = delegate;
        }

        public int read() throws IOException {
            int c = startroot.read();
            if(c==-1)
            {
                c = delegate.read();
            }
            if(c==-1)
            {
                c = endroot.read();
            }
            return c;
        }

    }

    public LogParser() {
        inputFactory = XMLInputFactory.newInstance();
    }

    public void read() throws Exception {
        is = new XMLStream(new FileInputStream(new File(
            "./myfile.log")));
        xmlReader = inputFactory.createXMLStreamReader(is);

        while (xmlReader.hasNext()) {
            printEvent(xmlReader);
            xmlReader.next();
        }
        xmlReader.close();

    }

    public void printEvent(XMLStreamReader xmlr) throws Exception {
        switch (xmlr.getEventType()) {
        case XMLStreamConstants.END_DOCUMENT:
            System.out.println("finished");
            break;
        case XMLStreamConstants.START_ELEMENT:
            System.out.print("<");
            printName(xmlr);
            printNamespaces(xmlr);
            printAttributes(xmlr);
            System.out.print(">");
            if(rootElement==null && depth==1)
            {
                rootElement = xmlr.getName();
            }
            depth++;
            break;
        case XMLStreamConstants.END_ELEMENT:
            System.out.print("</");
            printName(xmlr);
            System.out.print(">");
            depth--;
            if(depth==1 && rootElement.equals(xmlr.getName()))
            {
                rootElement=null;
                System.out.println("finished element");
            }
            break;
        case XMLStreamConstants.SPACE:
        case XMLStreamConstants.CHARACTERS:
            int start = xmlr.getTextStart();
            int length = xmlr.getTextLength();
            System.out
                    .print(new String(xmlr.getTextCharacters(), start, length));
            break;

        case XMLStreamConstants.PROCESSING_INSTRUCTION:
            System.out.print("<?");
            if (xmlr.hasText())
                System.out.print(xmlr.getText());
            System.out.print("?>");
            break;

        case XMLStreamConstants.CDATA:
            System.out.print("<![CDATA[");
            start = xmlr.getTextStart();
            length = xmlr.getTextLength();
            System.out
                    .print(new String(xmlr.getTextCharacters(), start, length));
            System.out.print("]]>");
            break;

        case XMLStreamConstants.COMMENT:
            System.out.print("<!--");
            if (xmlr.hasText())
                System.out.print(xmlr.getText());
            System.out.print("-->");
            break;

        case XMLStreamConstants.ENTITY_REFERENCE:
            System.out.print(xmlr.getLocalName() + "=");
            if (xmlr.hasText())
                System.out.print("[" + xmlr.getText() + "]");
            break;

        case XMLStreamConstants.START_DOCUMENT:
            System.out.print("<?xml");
            System.out.print(" version='" + xmlr.getVersion() + "'");
            System.out.print(" encoding='" + xmlr.getCharacterEncodingScheme()
                    + "'");
            if (xmlr.isStandalone())
                System.out.print(" standalone='yes'");
            else
                System.out.print(" standalone='no'");
            System.out.print("?>");
            break;

        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            new LogParser().read();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private static void printName(XMLStreamReader xmlr) {
        if (xmlr.hasName()) {
            System.out.print(getName(xmlr));
        }
    }

    private static String getName(XMLStreamReader xmlr) {
        if (xmlr.hasName()) {
            String prefix = xmlr.getPrefix();
            String uri = xmlr.getNamespaceURI();
            String localName = xmlr.getLocalName();
            return getName(prefix, uri, localName);
        }
        return null;
    }

    private static String getName(String prefix, String uri, String localName) {
        String name = "";
        if (uri != null && !("".equals(uri)))
            name += "['" + uri + "']:";
        if (prefix != null)
            name += prefix + ":";
        if (localName != null)
            name += localName;
        return name;
    }   

    private static void printAttributes(XMLStreamReader xmlr) {
        for (int i = 0; i < xmlr.getAttributeCount(); i++) {
            printAttribute(xmlr, i);
        }
    }

    private static void printAttribute(XMLStreamReader xmlr, int index) {
        String prefix = xmlr.getAttributePrefix(index);
        String namespace = xmlr.getAttributeNamespace(index);
        String localName = xmlr.getAttributeLocalName(index);
        String value = xmlr.getAttributeValue(index);
        System.out.print(" ");
        System.out.print(getName(prefix, namespace, localName));
        System.out.print("='" + value + "'");
    }

    private static void printNamespaces(XMLStreamReader xmlr) {
        for (int i = 0; i < xmlr.getNamespaceCount(); i++) {
            printNamespace(xmlr, i);
        }
    }

    private static void printNamespace(XMLStreamReader xmlr, int index) {
        String prefix = xmlr.getNamespacePrefix(index);
        String uri = xmlr.getNamespaceURI(index);
        System.out.print(" ");
        if (prefix == null)
            System.out.print("xmlns='" + uri + "'");
        else
            System.out.print("xmlns:" + prefix + "='" + uri + "'");
    }

}
+1

, :

<?xml version="1.0"?>
<documents>
    ... document 1 ...
    ... document 2 ...
</documents>

, XML (<?xml ...?>). , , , <?xml

0

( , , ), ascii (. ).

, ( ), , , EOM.

0

( ). , , imo,

, DocumentSplittingInputStream, InputStream ( ...). closeTag, node, . int matchCount -, . boolean, baseInputStreamNotFinished, true

read():

  • , matchCount == closeTag.length, , matchCount -1, return -1
  • matchCount == -1, matchCount = 0, read() , -1 '<' ( xml ) . , , , xml , , , - , " ".
  • , int ( closeTag [matchCount]), increment matchCount, reset matchCount )

, , . , , -1, , "baseInputStreamNotFinished" false.

, , , .

- , xstream:

DocumentSplittingInputStream dsis = new DocumentSplittingInputStream(underlyingInputStream);
while (dsis.underlyingInputStreamNotFinished()) {
    MyObject mo = xstream.fromXML(dsis);
    mo.doSomething(); // or something.doSomething(mo);
}

0

- , , , , , , () Reader

0

. -, , ( ) XML- HTTP- GET. String , user467257. :

public class AnotherSplittingInputStream extends InputStream {
    private final InputStream realStream;
    private final byte[] closeTag;

    private int matchCount;
    private boolean realStreamFinished;
    private boolean reachedCloseTag;

    public AnotherSplittingInputStream(InputStream realStream, String closeTag) {
        this.realStream = realStream;
        this.closeTag = closeTag.getBytes();
    }

    @Override
    public int read() throws IOException {
        if (reachedCloseTag) {
            return -1;
        }

        if (matchCount == closeTag.length) {
            matchCount = 0;
            reachedCloseTag = true;
            return -1;
        }

        int ch = realStream.read();
        if (ch == -1) {
            realStreamFinished = true;
        }
        else if (ch == closeTag[matchCount]) {
            matchCount++;
        } else {
            matchCount = 0;
        }
        return ch;
    }

    public boolean hasMoreData() {
        if (realStreamFinished == true) {
            return false;
        } else {
            reachedCloseTag = false;
            return true;
        }
    }
}

:

String xml =
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
        "<root>first root</root>" +
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
        "<root>second root</root>";
ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes());
SplittingInputStream splitter = new SplittingInputStream(is, "</root>");
BufferedReader reader = new BufferedReader(new InputStreamReader(splitter));

while (splitter.hasMoreData()) {
    System.out.println("Starting next stream");
    String line = null;
    while ((line = reader.readLine()) != null) {
        System.out.println("line ["+line+"]");
    }
}
0

JAXB- :

MultiInputStream.java

public class MultiInputStream extends InputStream {
    private final Reader source;
    private final StringReader startRoot = new StringReader("<root>");
    private final StringReader endRoot = new StringReader("</root>");

    public MultiInputStream(Reader source) {
        this.source = source;
    }

    @Override
    public int read() throws IOException {
        int count = startRoot.read();
        if (count == -1) {
            count = source.read();
        }
        if (count == -1) {
            count = endRoot.read();
        }
        return count;
    }
}

MultiEventReader.java

public class MultiEventReader implements XMLEventReader {

    private final XMLEventReader reader;
    private boolean isXMLEvent = false;
    private int level = 0;

    public MultiEventReader(XMLEventReader reader) throws XMLStreamException {
        this.reader = reader;
        startXML();
    }

    private void startXML() throws XMLStreamException {
        while (reader.hasNext()) {
            XMLEvent event = reader.nextEvent();
            if (event.isStartElement()) {
                return;
            }
        }
    }

    public boolean hasNextXML() {
        return reader.hasNext();
    }

    public void nextXML() throws XMLStreamException {
        while (reader.hasNext()) {
            XMLEvent event = reader.peek();
            if (event.isStartElement()) {
                isXMLEvent = true;
                return;
            }
            reader.nextEvent();
        }
    }

    @Override
    public XMLEvent nextEvent() throws XMLStreamException {
        XMLEvent event = reader.nextEvent();
        if (event.isStartElement()) {
            level++;
        }
        if (event.isEndElement()) {
            level--;
            if (level == 0) {
                isXMLEvent = false;
            }
        }
        return event;
    }

    @Override
    public boolean hasNext() {
        return isXMLEvent;
    }

    @Override
    public XMLEvent peek() throws XMLStreamException {
        XMLEvent event = reader.peek();
        if (level == 0) {
            while (event != null && !event.isStartElement() && reader.hasNext()) {
                reader.nextEvent();
                event = reader.peek();
            }
        }
        return event;
    }

    @Override
    public String getElementText() throws XMLStreamException {
        throw new NotImplementedException();
    }

    @Override
    public XMLEvent nextTag() throws XMLStreamException {
        throw new NotImplementedException();
    }

    @Override
    public Object getProperty(String name) throws IllegalArgumentException {
        throw new NotImplementedException();
    }

    @Override
    public void close() throws XMLStreamException {
        throw new NotImplementedException();
    }

    @Override
    public Object next() {
        throw new NotImplementedException();
    }

    @Override
    public void remove() {
        throw new NotImplementedException();
    }
}

Message.java

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Message")
public class Message {

    public Message() {
    }

    @XmlAttribute(name = "ID", required = true)
    protected long id;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Message{id=" + id + '}';
    }
}

Read multiple posts:

public static void main(String[] args) throws Exception{

    StringReader stringReader = new StringReader(
            "<Message ID=\"123\" />\n" +
            "<Message ID=\"321\" />"
    );

    JAXBContext context = JAXBContext.newInstance(Message.class);
    Unmarshaller unmarshaller = context.createUnmarshaller();

    XMLInputFactory inputFactory = XMLInputFactory.newFactory();
    MultiInputStream multiInputStream = new MultiInputStream(stringReader);
    XMLEventReader xmlEventReader = inputFactory.createXMLEventReader(multiInputStream);
    MultiEventReader multiEventReader = new MultiEventReader(xmlEventReader);

    while (multiEventReader.hasNextXML()) {
        Object message = unmarshaller.unmarshal(multiEventReader);
        System.out.println(message);
        multiEventReader.nextXML();
    }
}

results:

Message{id=123}
Message{id=321}
0
source

Source: https://habr.com/ru/post/1709300/


All Articles