![JAR search and dependency download from the Maven repository](/logo.png)
org.xmlpull.b5.XmlPullInfosetBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xpp5 Show documentation
Show all versions of xpp5 Show documentation
XML Pull parser library developed by extreme lab
package org.xmlpull.b5;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import org.xmlpull.infoset.XmlAttribute;
import org.xmlpull.infoset.XmlBuilderException;
import org.xmlpull.infoset.XmlCharacters;
import org.xmlpull.infoset.XmlComment;
import org.xmlpull.infoset.XmlContainer;
import org.xmlpull.infoset.XmlDocument;
import org.xmlpull.infoset.XmlElement;
import org.xmlpull.infoset.XmlInfosetBuilder;
import org.xmlpull.infoset.XmlNamespace;
import org.xmlpull.infoset.XmlPullSerializable;
import org.xmlpull.infoset.impl.XmlDocumentImpl;
//import org.xmlpull.infoset.impl.XmlElementImpl;
import org.xmlpull.infoset.impl.XmlElementWithViewsImpl;
import org.xmlpull.infoset.impl.XmlNamespaceImpl;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
//TODO: add equals() and hashcode()
//TODO: think about how to do gneralize XmlSerialziable (to simplify serialize()
//TODO: in XmlElement use String namespaceName and do not use XmlNamespace namespace (except for getNamespace()?
// NOTE: that XML infoset requires prefix information to be present even if not needed ....
/**
* Implementation of generic builder that uses XmlPull API to access current
* default XmlPullParser and XmlSerializer. By default builder is using
* non-validating namespaces enabled pull parser with next() method with to
* build tree consisting only of XmlDocument, XmlElemenet and String nodes. In
* future additional options may be available to change builder behavior and to
* generate any desired subset of XML Information Set
*
* @version $Revision: 1.9 $
* @author Aleksander Slominski
*
*/
public class XmlPullInfosetBuilder extends XmlInfosetBuilder {
private final static String PROPERTY_XMLDECL_STANDALONE = "http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone";
private final static String PROPERTY_XMLDECL_VERSION = "http://xmlpull.org/v1/doc/properties.html#xmldecl-version";
private boolean readOnly;
private boolean useComments;
private boolean usePIs;
private boolean wrapCharacters;
private boolean useViews;
private boolean provideDom2;
protected XmlPullParserFactory factory;
public XmlPullInfosetBuilder() throws XmlBuilderException {
try {
factory = XmlPullParserFactory.newInstance(System
.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
factory.setNamespaceAware(true);
} catch (XmlPullParserException ex) {
throw new XmlBuilderException("could not create XmlPull factory:"
+ ex, ex);
}
}
public XmlPullInfosetBuilder(XmlPullParserFactory factory)
throws XmlBuilderException {
if (factory == null) {
throw new IllegalArgumentException();
}
this.factory = factory;
// try {
this.factory.setNamespaceAware(true);
// } catch(XmlPullParserException ex) {
// throw new XmlBuilderException("could not create XmlPull factory:"+ex,
// ex);
// }
}
/**
* Method get XmlPull factory that is used by this builder.
*/
public XmlPullParserFactory getFactory() throws XmlBuilderException {
return factory;
}
public void setFeature(String featureName, boolean value) throws XmlBuilderException {
if (featureName.equals(FEATURE_READ_ONLY)) {
readOnly = value;
} else if (featureName.equals(FEATURE_BUILD_COMMENTS)) {
useComments = value;
} else if (featureName.equals(FEATURE_BUILD_PROCESSING_INSTRUCTIONS)) {
usePIs = value;
} else if (featureName.equals(FEATURE_WRAP_CHARACTERS)) {
wrapCharacters = value;
} else if (featureName.equals(FEATURE_VIEWS)) {
useViews = value;
} else if (featureName.equals(FEATURE_BUILD_DOM2)) {
provideDom2 = value;
} else {
throw new XmlBuilderException("feature '" + featureName + "' not recognized");
}
}
public XmlDocument newDocument(String version, Boolean standalone,
String characterEncoding) {
return new XmlDocumentImpl(version, standalone, characterEncoding);
}
public XmlElement newFragment(String elementName) {
return new XmlElementWithViewsImpl((XmlNamespace) null, elementName);
}
public XmlElement newFragment(String elementNamespaceName,
String elementName) {
return new XmlElementWithViewsImpl(elementNamespaceName, elementName);
}
public XmlElement newFragment(XmlNamespace elementNamespace,
String elementName) {
return new XmlElementWithViewsImpl(elementNamespace, elementName);
}
// public abstract XmlNamespace newNamespace(String namespaceName);
// public abstract XmlNamespace newNamespace(String prefix, String
// namespaceName);
public XmlNamespace newNamespace(String namespaceName) {
return new XmlNamespaceImpl(null, namespaceName);
}
public XmlNamespace newNamespace(String prefix, String namespaceName) {
return new XmlNamespaceImpl(prefix, namespaceName);
}
/**
* Parse document - parser must be in START_DOCUMENT state.
*/
public XmlDocument parse(XmlPullParser pp) throws XmlBuilderException {
XmlDocument doc = parseDocumentStart(pp);
XmlElement root = parseFragment(pp);
doc.setDocumentElement(root);
// TODO parseDocumentEnd() - parse epilog with nextToken();
return doc;
}
/**
* Will convert current parser state into event representing XML Infoset
* item:
*
* - START_Document: XmlDocument without root element
*
- START_TAG: XmlElement without children
*
- TEXT: String or XmlCHaracters depending on builder mode
*
- additional states to corresponding XML Infoset items (when
* implemented!)
*
*/
public Object parseItem(XmlPullParser pp) throws XmlBuilderException {
try {
int eventType = pp.getEventType();
if (eventType == XmlPullParser.START_TAG) {
return parseStartTag(pp);
} else if (eventType == XmlPullParser.TEXT) {
return pp.getText();
} else if (eventType == XmlPullParser.START_DOCUMENT) {
return parseDocumentStart(pp);
} else {
throw new XmlBuilderException(
"currently unsupported event type "
+ XmlPullParser.TYPES[eventType]
+ pp.getPositionDescription());
}
} catch (XmlPullParserException e) {
throw new XmlBuilderException("could not parse XML item", e);
}
}
private XmlDocument parseDocumentStart(XmlPullParser pp) {
// sourceForNode.next();
XmlDocument doc = null;
try {
if (pp.getEventType() != XmlPullParser.START_DOCUMENT) {
throw new XmlBuilderException(
"parser must be positioned on beginning of document"
+ " and not " + pp.getPositionDescription());
}
// TODO use nextToken()
pp.next();
String xmlDeclVersion = (String) pp
.getProperty(PROPERTY_XMLDECL_VERSION);
Boolean xmlDeclStandalone = (Boolean) pp
.getProperty(PROPERTY_XMLDECL_STANDALONE);
;
String characterEncoding = pp.getInputEncoding();
doc = new XmlDocumentImpl(xmlDeclVersion, xmlDeclStandalone,
characterEncoding);
} catch (XmlPullParserException e) {
throw new XmlBuilderException(
"could not parse XML document prolog", e);
} catch (IOException e) {
throw new XmlBuilderException("could not read XML document prolog",
e);
}
return doc;
}
/**
* Parse fragment - parser must be on START_TAG. After parsing is on
* corresponding END_TAG.
*/
public XmlElement parseFragment(XmlPullParser pp)
throws XmlBuilderException {
try {
int depth = pp.getDepth();
int eventType = pp.getEventType();
if (eventType != XmlPullParser.START_TAG) {
throw new XmlBuilderException(
"expected parser to be on start tag and not "
+ XmlPullParser.TYPES[eventType]
+ pp.getPositionDescription());
}
// int level = depth + 1;
XmlElement curElem = parseStartTag(pp);
while (true) {
eventType = pp.next();
if (eventType == XmlPullParser.START_TAG) {
XmlElement child = parseStartTag(pp);
curElem.addElement(child);
curElem = child;
} else if (eventType == XmlPullParser.END_TAG) {
XmlContainer parent = curElem.getParent();
if (parent == null) {
if (pp.getDepth() != depth) {
throw new XmlBuilderException("unbalanced input"
+ pp.getPositionDescription());
}
return curElem;
}
curElem = (XmlElement) parent;
// --level;
// curElem = curElem.parent;
} else if (eventType == XmlPullParser.TEXT) {
curElem.addChild(pp.getText());
} else if (eventType == XmlPullParser.COMMENT) {
// TODO
}
}
} catch (XmlPullParserException e) {
throw new XmlBuilderException("could not build tree from XML", e);
} catch (IOException e) {
throw new XmlBuilderException("could not read XML tree content", e);
}
}
/**
* Parser must be on START_TAG and this method will convert START_TAG
* content into XmlELement. Parser location is not changed.
*/
public XmlElement parseStartTag(XmlPullParser pp)
throws XmlBuilderException {
try {
// assert pp.getEventType() == XmlPullParser.START_TAG;
if (pp.getEventType() != XmlPullParser.START_TAG) {
throw new XmlBuilderException(
"parser must be on START_TAG and not "
+ pp.getPositionDescription());
}
String elNsPrefix = pp.getPrefix();
XmlNamespace elementNs = new XmlNamespaceImpl(elNsPrefix, pp
.getNamespace());
XmlElement el = new XmlElementWithViewsImpl(elementNs, pp.getName());
// add namespaces declarations (if any)
for (int i = pp.getNamespaceCount(pp.getDepth() - 1); i < pp
.getNamespaceCount(pp.getDepth()); i++) {
// TODO think about changing XmlPull to return "" in this case
// ... or
// not
String prefix = pp.getNamespacePrefix(i);
el.declareNamespace(prefix == null ? "" : prefix, pp
.getNamespaceUri(i));
}
// add attributes and namespaces
for (int i = 0; i < pp.getAttributeCount(); i++) {
el.setAttribute(pp.getAttributeType(i), pp
.getAttributePrefix(i), pp.getAttributeNamespace(i), pp
.getAttributeName(i), pp.getAttributeValue(i), pp
.isAttributeDefault(i) == false);
}
return el;
} catch (XmlPullParserException e) {
throw new XmlBuilderException("could not parse XML start tag", e);
// } catch (IOException e) {
// throw new XmlBuilderException("could not read XML start tag" ,e);
}
}
public XmlDocument parseLocation(String locationUrl)
throws XmlBuilderException {
// TODO: if first is "/" try opening file
URL url = null;
try {
url = new URL(locationUrl);
} catch (MalformedURLException e) {
throw new XmlBuilderException("could not parse URL " + locationUrl,
e);
}
try {
return parseInputStream(url.openStream());
} catch (IOException e) {
throw new XmlBuilderException("could not open connection to URL "
+ locationUrl, e);
}
}
public XmlElement parseFragmentFromInputStream(InputStream is)
throws XmlBuilderException {
XmlPullParser pp = null;
try {
pp = factory.newPullParser();
pp.setInput(is, null);
// set options ...
try {
pp.nextTag();
} catch (IOException e) {
throw new XmlBuilderException(
"IO error when starting to parse input stream", e);
}
} catch (XmlPullParserException e) {
throw new XmlBuilderException(
"could not start parsing input stream", e);
}
return parseFragment(pp);
}
public XmlElement parseFragmentFromInputStream(InputStream is,
String encoding) throws XmlBuilderException {
XmlPullParser pp = null;
try {
pp = factory.newPullParser();
pp.setInput(is, encoding);
// set options ...
try {
pp.nextTag();
} catch (IOException e) {
throw new XmlBuilderException(
"IO error when starting to parse input stream (encoding="
+ encoding + ")", e);
}
} catch (XmlPullParserException e) {
throw new XmlBuilderException(
"could not start parsing input stream (encoding="
+ encoding + ")", e);
}
return parseFragment(pp);
}
public XmlElement parseFragmentFromReader(Reader reader)
throws XmlBuilderException {
XmlPullParser pp = null;
try {
pp = factory.newPullParser();
pp.setInput(reader);
// set options ...
try {
pp.nextTag();
} catch (IOException e) {
throw new XmlBuilderException(
"IO error when starting to parse from reader", e);
}
} catch (XmlPullParserException e) {
throw new XmlBuilderException(
"could not start parsing input from reader", e);
}
return parseFragment(pp);
}
public XmlDocument parseInputStream(InputStream is)
throws XmlBuilderException {
XmlPullParser pp = null;
try {
pp = factory.newPullParser();
pp.setInput(is, null);
// set options ...
} catch (XmlPullParserException e) {
throw new XmlBuilderException(
"could not start parsing input stream", e);
}
return parse(pp);
}
public XmlDocument parseInputStream(InputStream is, String encoding)
throws XmlBuilderException {
XmlPullParser pp = null;
try {
pp = factory.newPullParser();
pp.setInput(is, encoding);
// set options ...
} catch (XmlPullParserException e) {
throw new XmlBuilderException(
"could not start parsing input stream (encoding="
+ encoding + ")", e);
}
return parse(pp);
}
public XmlDocument parseReader(Reader reader) throws XmlBuilderException {
XmlPullParser pp = null;
try {
pp = factory.newPullParser();
pp.setInput(reader);
// set options ...
} catch (XmlPullParserException e) {
throw new XmlBuilderException(
"could not start parsing input from reader", e);
}
return parse(pp);
}
/**
* Move parser from START_TAG to the corresponding END_TAG which means that
* XML sub tree is skipped.
*
* @param pp
* a XmlPullParser
*
* @exception XmlBuilderException
*
*/
public void skipSubTree(XmlPullParser pp) throws XmlBuilderException {
try {
pp.require(XmlPullParser.START_TAG, null, null);
int level = 1;
while (level > 0) {
int eventType = pp.next();
if (eventType == XmlPullParser.END_TAG) {
--level;
} else if (eventType == XmlPullParser.START_TAG) {
++level;
}
}
} catch (XmlPullParserException e) {
throw new XmlBuilderException("could not skip subtree", e);
} catch (IOException e) {
throw new XmlBuilderException("IO error when skipping subtree", e);
}
}
/**
* Serialize XML Infoset item including serializing of children. If item is
* Collection all items in collection are serialized by recursively calling
* this function. This method assumes that item is either interface defined
* in XB1 API, class String, or that item implements XmlSerializable
* otherwise IllegalArgumentException is thrown.
*/
public void serialize(Object item, XmlSerializer serializer) throws XmlBuilderException {
if (item instanceof Collection) {
Collection c = (Collection) item;
for (Iterator i = c.iterator(); i.hasNext();) {
serialize(i.next(), serializer);
}
} else if (item instanceof XmlContainer) {
serializeContainer((XmlContainer) item, serializer);
} else {
serializeItem(item, serializer);
}
}
private void serializeContainer(XmlContainer node, XmlSerializer serializer) {
if (node instanceof XmlPullSerializable) {
try {
((XmlPullSerializable) node).serialize(serializer);
} catch (IOException e) {
throw new XmlBuilderException("could not serialize node "
+ node + ": " + e, e);
}
} else if (node instanceof XmlDocument) {
serializeDocument((XmlDocument) node, serializer);
} else if (node instanceof XmlElement) {
serializeFragment((XmlElement) node, serializer);
} else {
throw new IllegalArgumentException(
"could not serialzie unknown XML container "
+ node.getClass());
}
}
/**
* Serialize XML Infoset item without serializing any of children.
* This method assumes that item is either interface defined in XB1 API,
* class String, or item that implements XmlSerializable otherwise
* IllegalArgumentException is thrown.
*/
public void serializeItem(Object item, XmlSerializer ser) throws XmlBuilderException {
serializeItem(null, item, ser);
}
public void serializeItem(XmlElement parent, Object item, XmlSerializer ser) throws XmlBuilderException {
try {
if (item instanceof XmlPullSerializable) {
// ((XmlSerializable)item).serialize(ser);
try {
((XmlPullSerializable) item).serialize(ser);
} catch (IOException e) {
throw new XmlBuilderException("could not serialize item "
+ item + ": " + e, e);
}
} else if (item instanceof String) {
ser.text(item.toString());
} else if (item instanceof XmlCharacters) {
ser.text(((XmlCharacters) item).getText());
} else if (item instanceof XmlComment) {
ser.comment(((XmlComment) item).getContent());
} else {
String context = "";
if(parent != null) {
context = getHeritage(parent);
}
throw new IllegalArgumentException("could not serialize "
+ (item != null ? item.getClass() : item));
}
} catch (IOException e) {
throw new XmlBuilderException("serializing XML start tag failed", e);
}
}
/**
* Write XML start tag with information provided in XML element.
*
* @param el
* a XmlElement
* @param ser
* a XmlSerializer
*
* @exception XmlBuilderException
*
*/
public void serializeStartTag(XmlElement el, XmlSerializer ser) {
try {
// declare namespaces
XmlNamespace elNamespace = el.getNamespace();
String elPrefix = (elNamespace != null)
? elNamespace.getPrefix()
: "";
if (elPrefix == null) {
elPrefix = "";
}
String nToDeclare = null;
if (el.hasNamespaceDeclarations()) {
//Iterator iter = el.namespaces().iterator();
//while (iter.hasNext()) {
//XmlNamespace n = iter.next();
for (XmlNamespace n : el.namespaces()) {
String nPrefix = n.getPrefix();
if (!elPrefix.equals(nPrefix)) {
ser.setPrefix(nPrefix, n.getName());
} else {
nToDeclare = n.getName();
}
}
}
// make sure that preferred element prefix is declared last so it is
// picked up by serializer
if (nToDeclare != null) {
ser.setPrefix(elPrefix, nToDeclare);
} else {
if (elNamespace != null) {
// first check that it needs to be declared - will declaring
// change
// anything?
String namespaceName = elNamespace.getName();
if (namespaceName == null) {
namespaceName = "";
}
String serPrefix = null;
if (namespaceName.length() > 0) {
ser.getPrefix(namespaceName, false);
}
if (serPrefix == null) {
serPrefix = "";
}
if (serPrefix != elPrefix && !serPrefix.equals(elPrefix)) {
// the prefix was not declared on current elment but
// just to enforce
// prefix choice ...
ser.setPrefix(elPrefix, namespaceName);
}
}
}
ser.startTag(el.getNamespaceName(), el.getName());
if (el.hasAttributes()) {
//Iterator iter = el.attributes();
//while (iter.hasNext()) {
//XmlAttribute a = (XmlAttribute) iter.next();
for (XmlAttribute a : el.attributes()) {
if (a instanceof XmlPullSerializable) {
((XmlPullSerializable) a).serialize(ser);
} else {
ser.attribute(a.getNamespaceName(), a.getName(), a
.getValue());
}
}
}
} catch (IOException e) {
throw new XmlBuilderException("serializing XML start tag failed", e);
}
}
/**
* Write XML end tag with information provided in XML element.
*
* @param el
* a XmlElement
* @param ser
* a XmlSerializer
*
* @exception XmlBuilderException
*
*/
public void serializeEndTag(XmlElement el, XmlSerializer ser) {
try {
ser.endTag(el.getNamespaceName(), el.getName());
} catch (IOException e) {
throw new XmlBuilderException("serializing XML end tag failed", e);
}
}
// TODO: would iit be simple make XmlContainer serialziable and use it to
// serialize ....
// TODO but would it be more flexible?
private void serializeDocument(XmlDocument doc, XmlSerializer ser) {
try {
ser.startDocument(doc.getCharacterEncodingScheme(), doc
.isStandalone());
} catch (IOException e) {
throw new XmlBuilderException(
"serializing XML document start failed", e);
}
if (doc.getDocumentElement() != null) {
serializeFragment(doc.getDocumentElement(), ser);
} else {
throw new XmlBuilderException(
"could not serialize document without root element " + doc
+ ": ");
}
try {
ser.endDocument();
} catch (IOException e) {
throw new XmlBuilderException(
"serializing XML document end failed", e);
}
}
private void serializeFragment(XmlElement el, XmlSerializer ser) {
serializeStartTag(el, ser);
// try {
if (el.hasChildren()) {
//Iterator iter = el.children().iterator();
//while (iter.hasNext()) {
// Object child = iter.next();
for (Object child : el.children()) {
if (child instanceof XmlPullSerializable) {
// ((XmlSerializable)child).serialize(ser);
try {
((XmlPullSerializable) child).serialize(ser);
} catch (IOException e) {
throw new XmlBuilderException(
"could not serialize item " + child + ": " + e,
e);
}
} else if (child instanceof XmlElement) {
// if("event-sink-epr".equals(((XmlElement)child).getName())){ // check there is a loop
//// XmlContainer parentEl = ((XmlElement) child).getParent();
//// while (parentEl != null) {
//// if (parentEl == child) {
//// throw new IllegalStateException("detected loop " + child);
//// }
//// if(parentEl instanceof XmlElement) {
//// parentEl = ((XmlElement)parentEl).getParent();
//// } else {
//// break;
//// }
//// }
// System.err.println(child);
// }
serializeFragment((XmlElement) child, ser);
} else {
//if (child != null) {
serializeItem(el, child, ser);
//} else {
// throw new XmlBuilderException(
// "could not serialize null in element " + getHeritage(el));
//}
}
}
}
// } catch (IOException e) {
// throw new XmlBuilderException("serializing XML element children
// failed",
// e);
// }
serializeEndTag(el, ser);
}
/**
* Print parent of parent of parent ...
*/
private String getHeritage(XmlElement el) {
XmlContainer parent = el.getParent();
String path;
if (parent instanceof XmlElement) {
path = getHeritage((XmlElement) parent) + "/" + el.getName();
} else {
path = "/" + el.getName();
}
return path;
}
public void serializeToOutputStream(Object item, // XmlContainer node,
OutputStream os, String encoding) throws XmlBuilderException {
XmlSerializer ser = null;
try {
ser = factory.newSerializer();
ser.setOutput(os, encoding);
} catch (Exception e) {
throw new XmlBuilderException(
"could not serialize node to output stream" + " (encoding="
+ encoding + ")", e);
}
serialize(item, ser);
try {
ser.flush();
} catch (IOException e) {
throw new XmlBuilderException("could not flush output", e);
}
}
public void serializeToWriter(Object item, Writer writer)
throws XmlBuilderException {
XmlSerializer ser = null;
try {
ser = factory.newSerializer();
ser.setOutput(writer);
} catch (Exception e) {
throw new XmlBuilderException("could not serialize node to writer",
e);
}
serialize(item, ser);
try {
ser.flush();
} catch (IOException e) {
throw new XmlBuilderException("could not flush output", e);
}
}
public void serializeToWriter(Object item, Writer writer, boolean pretty)
throws XmlBuilderException {
XmlSerializer ser = null;
try {
ser = factory.newSerializer();
ser.setOutput(writer);
ser.setProperty("http://xmlpull.org/v1/doc/properties.html#serializer-indentation", " ");
} catch (Exception e) {
throw new XmlBuilderException("could not serialize node to writer",
e);
}
serialize(item, ser);
try {
ser.flush();
} catch (IOException e) {
throw new XmlBuilderException("could not flush output", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy