1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-06-30 07:14:49 +02:00
Smack/smack-xmlparser-stax/src/main/java/org/jivesoftware/smack/xml/stax/StaxXmlPullParser.java
Florian Schmaus 4133eb175c Replace XPP3 by XmlPullParser interface wrapping StAX and XPP3
Introducing Smack's own XmlPullParser interface which tries to stay as
compatible as possible to XPP3. The interface is used to either wrap
StAX's XMLStreamReader if Smack is used on Java SE, and XPP3's
XmlPullParser if Smack is used on on Android.

Fixes SMACK-591.

Also introduce JUnit 5 and non-strict javadoc projects.
2019-05-06 22:10:50 +02:00

302 lines
8.4 KiB
Java

/**
*
* Copyright 2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.xml.stax;
import java.io.IOException;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
public final class StaxXmlPullParser implements XmlPullParser {
private final XMLStreamReader xmlStreamReader;
private int depth;
StaxXmlPullParser(XMLStreamReader xmlStreamReader) {
this.xmlStreamReader = xmlStreamReader;
}
@Override
public Object getProperty(String name) {
return xmlStreamReader.getProperty(name);
}
@Override
public String getInputEncoding() {
return xmlStreamReader.getEncoding();
}
@Override
public int getNamespaceCount() {
return xmlStreamReader.getNamespaceCount();
}
@Override
public String getNamespacePrefix(int pos) {
return xmlStreamReader.getNamespacePrefix(pos);
}
@Override
public String getNamespaceUri(int pos) {
return xmlStreamReader.getNamespaceURI(pos);
}
@Override
public String getNamespace(String prefix) {
if (prefix == null) {
prefix = XMLConstants.DEFAULT_NS_PREFIX;
}
NamespaceContext namespaceContext = xmlStreamReader.getNamespaceContext();
return namespaceContext.getNamespaceURI(prefix);
}
@Override
public int getDepth() {
return depth;
}
@Override
public String getPositionDescription() {
Location location = xmlStreamReader.getLocation();
return location.toString();
}
@Override
public int getLineNumber() {
Location location = xmlStreamReader.getLocation();
return location.getLineNumber();
}
@Override
public int getColumnNumber() {
Location location = xmlStreamReader.getLocation();
return location.getColumnNumber();
}
@Override
public boolean isWhiteSpace() {
return xmlStreamReader.isWhiteSpace();
}
@Override
public String getText() {
return xmlStreamReader.getText();
}
@Override
public String getNamespace() {
NamespaceContext namespaceContext = xmlStreamReader.getNamespaceContext();
String prefix = getPrefix();
return namespaceContext.getNamespaceURI(prefix);
}
@Override
public String getName() {
QName qname = getQName();
return qname.getLocalPart();
}
@Override
public QName getQName() {
return xmlStreamReader.getName();
}
@Override
public String getPrefix() {
return xmlStreamReader.getPrefix();
}
@Override
public int getAttributeCount() {
return xmlStreamReader.getAttributeCount();
}
@Override
public String getAttributeNamespace(int index) {
return xmlStreamReader.getAttributeNamespace(index);
}
@Override
public String getAttributeName(int index) {
QName qname = getAttributeQName(index);
if (qname == null) {
return null;
}
return qname.getLocalPart();
}
@Override
public QName getAttributeQName(int index) {
return xmlStreamReader.getAttributeName(index);
}
@Override
public String getAttributePrefix(int index) {
return xmlStreamReader.getAttributePrefix(index);
}
@Override
public String getAttributeType(int index) {
return xmlStreamReader.getAttributeType(index);
}
@Override
public String getAttributeValue(int index) {
return xmlStreamReader.getAttributeValue(index);
}
@Override
public String getAttributeValue(String namespace, String name) {
String namespaceURI = namespace;
String localName = name;
return xmlStreamReader.getAttributeValue(namespaceURI, localName);
}
@Override
public Event getEventType() {
int staxEventInt = xmlStreamReader.getEventType();
return staxEventIntegerToEvent(staxEventInt);
}
private boolean delayedDepthDecrement;
@Override
public Event next() throws XmlPullParserException {
preNextEvent();
int staxEventInt;
try {
staxEventInt = xmlStreamReader.next();
} catch (XMLStreamException e) {
throw new XmlPullParserException(e);
}
Event event = staxEventIntegerToEvent(staxEventInt);
switch (event) {
case START_ELEMENT:
depth++;
break;
case END_ELEMENT:
delayedDepthDecrement = true;
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
return event;
}
@Override
public String nextText() throws IOException, XmlPullParserException {
final String nextText;
try {
nextText = xmlStreamReader.getElementText();
} catch (XMLStreamException e) {
throw new XmlPullParserException(e);
}
// XMLStreamReader.getElementText() will forward to the next END_ELEMENT, hence we need to set
// delayedDepthDecrement to true.
delayedDepthDecrement = true;
return nextText;
}
@Override
public TagEvent nextTag() throws IOException, XmlPullParserException {
preNextEvent();
int staxEventInt;
try {
staxEventInt = xmlStreamReader.nextTag();
} catch (XMLStreamException e) {
throw new XmlPullParserException(e);
}
switch (staxEventInt) {
case XMLStreamConstants.START_ELEMENT:
depth++;
return TagEvent.START_ELEMENT;
case XMLStreamConstants.END_ELEMENT:
delayedDepthDecrement = true;
return TagEvent.END_ELEMENT;
default:
throw new AssertionError();
}
}
private void preNextEvent() {
if (delayedDepthDecrement) {
depth--;
delayedDepthDecrement = false;
assert depth >= 0;
}
}
private static Event staxEventIntegerToEvent(int staxEventInt) {
switch (staxEventInt) {
case XMLStreamConstants.START_ELEMENT:
return Event.START_ELEMENT;
case XMLStreamConstants.END_ELEMENT:
return Event.END_ELEMENT;
case XMLStreamConstants.PROCESSING_INSTRUCTION:
return Event.PROCESSING_INSTRUCTION;
case XMLStreamConstants.CHARACTERS:
return Event.TEXT_CHARACTERS;
case XMLStreamConstants.COMMENT:
return Event.COMMENT;
case XMLStreamConstants.SPACE:
return Event.IGNORABLE_WHITESPACE;
case XMLStreamConstants.START_DOCUMENT:
return Event.START_DOCUMENT;
case XMLStreamConstants.END_DOCUMENT:
return Event.END_DOCUMENT;
case XMLStreamConstants.ENTITY_REFERENCE:
return Event.ENTITY_REFERENCE;
case XMLStreamConstants.ATTRIBUTE:
return Event.OTHER;
case XMLStreamConstants.DTD:
return Event.OTHER;
case XMLStreamConstants.CDATA:
return Event.OTHER;
case XMLStreamConstants.NAMESPACE:
return Event.OTHER;
case XMLStreamConstants.NOTATION_DECLARATION:
return Event.OTHER;
case XMLStreamConstants.ENTITY_DECLARATION:
return Event.OTHER;
default:
throw new IllegalArgumentException("Unknown Stax event integer: " + staxEventInt);
}
}
@Override
public boolean supportsRoundtrip() {
// TODO: Is there a StAX parser implementation which does support roundtrip?
return false;
}
}