public Document parseDocument() throws DocumentException, IOException, XmlPullParserException {
        DocumentFactory df = getDocumentFactory();
        Document document = df.createDocument();
        Element parent = null;
        XmlPullParser pp = getXPPParser();
        int count = 0;
        while (true) {
            int type = -1;
            type = pp.nextToken();
            switch (type) {
                case XmlPullParser.PROCESSING_INSTRUCTION: {
                    String text = pp.getText();
                    int loc = text.indexOf(" ");
                    if (loc >= 0) {
                        document.addProcessingInstruction(text.substring(0, loc),
                                text.substring(loc + 1));
                    }
                    else {
                        document.addProcessingInstruction(text, "");
                    }
                    break;
                }
                case XmlPullParser.COMMENT: {
                    if (parent != null) {
                        parent.addComment(pp.getText());
                    }
                    else {
                        document.addComment(pp.getText());
                    }
                    break;
                }
                case XmlPullParser.CDSECT: {
                    String text = pp.getText();
                    if (parent != null) {
                        parent.addCDATA(text);
                    }
                    else {
                        if (!text.trim().isEmpty()) {
                            throw new DocumentException("Cannot have text content outside of the root document");
                        }
                    }
                    break;

                }
                case XmlPullParser.ENTITY_REF: {
                    String text = pp.getText();
                    if (parent != null) {
                        parent.addText(text);
                    }
                    else {
                        if (!text.trim().isEmpty()) {
                            throw new DocumentException("Cannot have an entityref outside of the root document");
                        }
                    }
                    break;
                }
                case XmlPullParser.END_DOCUMENT: {
                    return document;
                }
                case XmlPullParser.START_TAG: {
                    QName qname = (pp.getPrefix() == null) ? df.createQName(pp.getName(), pp.getNamespace()) : df.createQName(pp.getName(), pp.getPrefix(), pp.getNamespace());
                    Element newElement;

                    // Strip namespace from all default-namespaced elements if
                    // all ancestors have the same namespace and it's a content
                    // namespace.
                    boolean dropNamespace = false;
                    if (pp.getPrefix() == null && IGNORED_NAMESPACE_ON_STANZA.contains(qname.getNamespaceURI())) {
                        // Default namespaced element which is in a content namespace,
                        // so we'll drop. Example, stanzas, <message><body/></message>
                        dropNamespace = true;
                        for (Element el = parent; el != null; el = el.getParent()) {
                            final String defaultNS = el.getNamespaceForPrefix("").getURI();
                            if (defaultNS.isEmpty()) {
                                // We've cleared this one already, just bail.
                                break;
                            }
                            if (!defaultNS.equals(qname.getNamespaceURI())) {
                                // But if there's an ancestor element, we shouldn't drop
                                // after all. Example: forwarded message.
                                dropNamespace = false;
                                break;
                            }
                        }
                    }
                    if ( dropNamespace ) {
                        newElement = df.createElement(pp.getName());
                    }
                    else {
                        newElement = df.createElement(qname);
                    }
                    int nsStart = pp.getNamespaceCount(pp.getDepth() - 1);
                    int nsEnd = pp.getNamespaceCount(pp.getDepth());
                    for (int i = nsStart; i < nsEnd; i++) {
                        final String namespacePrefix = pp.getNamespacePrefix( i );
                        final String namespaceUri = pp.getNamespaceUri( i );
                        if ( namespacePrefix != null ) {
                            newElement.addNamespace(namespacePrefix, namespaceUri);
                        } else if ( parent == null && IGNORED_NAMESPACE_ON_STANZA.contains( namespaceUri ) ) {
                            // Don't copy.
                        } else if ( !(dropNamespace && namespaceUri.equals( qname.getNamespaceURI() ) ) ) {
                            // Do not include certain default namespace on the root-element ('stream') or stanza level. This makes stanzas re-usable between, for example, c2s and s2s.
                            newElement.addNamespace( "", namespaceUri );
                        }
                    }
                    for (int i = 0; i < pp.getAttributeCount(); i++) {
                        QName qa = (pp.getAttributePrefix(i) == null) ? df.createQName(pp.getAttributeName(i)) : df.createQName(pp.getAttributeName(i), pp.getAttributePrefix(i), pp.getAttributeNamespace(i));
                        newElement.addAttribute(qa, pp.getAttributeValue(i));
                    }
                    if (parent != null) {
                        parent.add(newElement);
                    }
                    else {
                        document.add(newElement);
                    }
                    parent = newElement;
                    count++;
                    break;
                }
                case XmlPullParser.END_TAG: {
                    if (parent != null) {
                        parent = parent.getParent();
                    }
                    count--;
                    if (count < 1) {
                        // Update the last time a Document was received
                        lastActive = System.currentTimeMillis();
                        return document;
                    }
                    break;
                }
                case XmlPullParser.TEXT: {
                    String text = pp.getText();
                    if (parent != null) {
                        parent.addText(text);
                    }
                    else {
                        if (!text.trim().isEmpty()) {
                            throw new DocumentException("Cannot have text content outside of the root document");
                        }
                    }
                    break;
                }
                default:
                {

                }
            }
        }
    }
Returns the last time a full Document was read or a heartbeat was received. Hearbeats
are represented as whitespaces or \n received while a Document is not being parsed.

@return the time in milliseconds when the last document or heartbeat was received.
xmppserver/src/main/java/org/dom4j/io/XMPPPacketReader.java