/* * eXist Open Source Native XML Database * Copyright (C) 2001-07 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * $Id$ */ package org.exist.memtree; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.Location; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.exist.numbering.NodeId; import org.exist.stax.ExtendedXMLStreamReader; import org.w3c.dom.Node; /** * Implementation of a StAX {@link javax.xml.stream.XMLStreamReader}, which wraps around * eXist's in-memory DOM. This class complements {@link org.exist.stax.EmbeddedXMLStreamReader} * which reads persistent documents. */ public class InMemoryXMLStreamReader implements ExtendedXMLStreamReader { protected DocumentImpl doc; protected int currentNode; protected int previous; protected NodeImpl rootNode; protected int state = XMLStreamReader.START_DOCUMENT; public InMemoryXMLStreamReader(DocumentImpl doc, NodeImpl node) { this.doc = doc; this.currentNode = -1; this.rootNode = node; } public Object getProperty(String name) throws IllegalArgumentException { if (name.equals(PROPERTY_NODE_ID)) { if (currentNode < 0 || currentNode >= doc.size) return null; doc.expand(); return doc.nodeId[currentNode]; } return null; } public int next() throws XMLStreamException { if (state != XMLStreamReader.END_ELEMENT) { previous = currentNode; } if (currentNode > -1) { int next = -1; if (state == XMLStreamReader.START_ELEMENT || state == XMLStreamReader.START_DOCUMENT) { next = doc.getFirstChildFor(currentNode); if (next < 0) { // no child nodes state = XMLStreamReader.END_ELEMENT; return state; } } if (next < 0) { next = doc.next[currentNode]; if (next < currentNode) { if (next == 0) state = XMLStreamReader.END_DOCUMENT; else state = XMLStreamReader.END_ELEMENT; currentNode = next; return state; } } currentNode = next; } else { currentNode = rootNode.getNodeNumber(); } switch (doc.nodeKind[currentNode]) { case Node.TEXT_NODE: state = XMLStreamReader.CHARACTERS; break; case Node.CDATA_SECTION_NODE: state = XMLStreamReader.CDATA; break; case Node.COMMENT_NODE: state = XMLStreamReader.COMMENT; break; case Node.PROCESSING_INSTRUCTION_NODE: state = XMLStreamReader.PROCESSING_INSTRUCTION; break; case Node.ELEMENT_NODE: state = XMLStreamReader.START_ELEMENT; break; } return state; } public void require(int type, String namespaceURI, String localName) throws XMLStreamException { } public String getElementText() throws XMLStreamException { if(getEventType() != START_ELEMENT) { throw new XMLStreamException( "parser must be on START_ELEMENT to read next text"); } int eventType = next(); StringBuffer content = new StringBuffer(); while(eventType != END_ELEMENT ) { if(eventType == CHARACTERS || eventType == CDATA || eventType == SPACE || eventType == ENTITY_REFERENCE) { content.append(getText()); } else if(eventType == PROCESSING_INSTRUCTION || eventType == COMMENT) { // skipping } else if(eventType == END_DOCUMENT) { throw new XMLStreamException("unexpected end of document when reading element text content"); } else if(eventType == START_ELEMENT) { throw new XMLStreamException( "element text content may not contain START_ELEMENT"); } else { throw new XMLStreamException( "Unexpected event type "+eventType); } eventType = next(); } return content.toString(); } public int nextTag() throws XMLStreamException { throw new UnsupportedOperationException(); } public boolean hasNext() throws XMLStreamException { return currentNode != rootNode.getNodeNumber() || state == XMLStreamReader.START_DOCUMENT || state == XMLStreamReader.START_ELEMENT; } public void close() throws XMLStreamException { } public String getNamespaceURI(String prefix) { return null; } public boolean isStartElement() { return state == XMLStreamReader.START_ELEMENT; } public boolean isEndElement() { return state == XMLStreamReader.END_ELEMENT; } public boolean isCharacters() { return state == XMLStreamReader.CHARACTERS; } public boolean isWhiteSpace() { return false; } public String getAttributeValue(String namespaceURI, String localName) { int attrCount = doc.getAttributesCountFor(currentNode); if (attrCount == 0) return null; int attrStart = doc.alpha[currentNode]; for (int i = 0; i < attrCount; i++) { org.exist.dom.QName qname = doc.attrName[attrStart + i]; if (namespaceURI.equals(qname.getNamespaceURI()) && localName.equals(qname.getLocalName())) return doc.attrValue[attrStart + i]; } return null; } public int getAttributeCount() { if (state != START_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); return doc.getAttributesCountFor(currentNode); } public org.exist.dom.QName getAttributeQName(int index) { if (state != START_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); if (index > getAttributeCount()) throw new ArrayIndexOutOfBoundsException("bad attribute index"); int attr = doc.alpha[currentNode]; return doc.attrName[attr + index]; } public QName getAttributeName(int index) { return getAttributeQName(index).toJavaQName(); } public String getAttributeNamespace(int index) { if (state != START_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); return getAttributeQName(index).getNamespaceURI(); } public String getAttributeLocalName(int index) { if (state != START_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); return getAttributeQName(index).getLocalName(); } public String getAttributePrefix(int index) { if (state != START_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); return getAttributeQName(index).getPrefix(); } public NodeId getAttributeId(int index) { if (state != START_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); if (index > getAttributeCount()) throw new ArrayIndexOutOfBoundsException("bad attribute index"); doc.expand(); int attr = doc.alpha[currentNode]; return doc.attrNodeId[attr + index]; } public String getAttributeType(int index) { if (state != START_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); if (index > getAttributeCount()) throw new ArrayIndexOutOfBoundsException("bad attribute index"); int attr = doc.alpha[currentNode]; int type = doc.attrType[attr + index]; switch (type) { case AttributeImpl.ATTR_ID_TYPE: return "ID"; case AttributeImpl.ATTR_IDREF_TYPE: return "IDREF"; case AttributeImpl.ATTR_IDREFS_TYPE: return "IDREFS"; default: return "CDATA"; } } public String getAttributeValue(int index) { if (state != START_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); if (index > getAttributeCount()) throw new ArrayIndexOutOfBoundsException("bad attribute index"); int attr = doc.alpha[currentNode]; return doc.attrValue[attr + index]; } public boolean isAttributeSpecified(int index) { if (state != START_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); return true; } public int getNamespaceCount() { if (state != START_ELEMENT && state != END_ELEMENT) throw new IllegalStateException("Cursor is not at an element"); return doc.getNamespacesCountFor(currentNode); } public String getNamespacePrefix(int index) { if (index > getNamespaceCount()) throw new ArrayIndexOutOfBoundsException("bad namespace index"); int ns = doc.alphaLen[currentNode]; org.exist.dom.QName nsQName = doc.namespaceCode[ns + index]; return nsQName.getLocalName(); } public String getNamespaceURI(int index) { if (index > getNamespaceCount()) throw new ArrayIndexOutOfBoundsException("bad namespace index"); int ns = doc.alphaLen[currentNode]; org.exist.dom.QName nsQName = doc.namespaceCode[ns + index]; return nsQName.getNamespaceURI(); } public NamespaceContext getNamespaceContext() { throw new UnsupportedOperationException(); } public int getEventType() { return state; } public String getText() { if (state == CHARACTERS || state == COMMENT || state == CDATA) return new String(doc.characters, doc.alpha[currentNode], doc.alphaLen[currentNode]); return ""; } public char[] getTextCharacters() { char[] ch = new char[doc.alphaLen[currentNode]]; System.arraycopy(doc.characters, doc.alpha[currentNode], ch, 0, ch.length); return ch; } public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException { throw new UnsupportedOperationException(); } public int getTextStart() { throw new UnsupportedOperationException(); } public int getTextLength() { throw new UnsupportedOperationException(); } public String getEncoding() { throw new UnsupportedOperationException(); } public boolean hasText() { return state == CHARACTERS || state == COMMENT || state == CDATA; } public Location getLocation() { throw new UnsupportedOperationException(); } public org.exist.dom.QName getQName() { if (state == START_ELEMENT || state == END_ELEMENT) { return doc.nodeName[currentNode]; } throw new IllegalStateException("Cursor is not at an element"); } public QName getName() { return getQName().toJavaQName(); } public String getLocalName() { return getQName().getLocalName(); } public boolean hasName() { return (state == START_ELEMENT || state == END_ELEMENT); } public String getNamespaceURI() { return getQName().getNamespaceURI(); } public String getPrefix() { return getQName().getPrefix(); } public String getVersion() { return "1.0"; } public boolean isStandalone() { return false; } public boolean standaloneSet() { return false; } public String getCharacterEncodingScheme() { return null; } public String getPITarget() { org.exist.dom.QName qn = doc.nodeName[currentNode]; return qn != null ? qn.getLocalName() : null; } public String getPIData() { return new String(doc.characters, doc.alpha[currentNode], doc.alphaLen[currentNode]); } }