All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.util.xml.AbstractXMLEventParser Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */

package gov.nasa.worldwind.util.xml;

import gov.nasa.worldwind.avlist.*;
import gov.nasa.worldwind.util.*;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.*;
import java.lang.reflect.Constructor;
import java.util.*;

/**
 * Base class for XML event parsers. Handles parsing control and creation of new parser instances.
 * 

* A parser holds the information parsed from the event stream. That information can be queried via the parser's * accessors. A parser typically does not maintain a reference to the event stream it parsed or the parser context used * during parsing. *

* Parsers are created when events of the associated type are encountered in the input stream. An {@link * #allocate(XMLEventParserContext, javax.xml.stream.events.XMLEvent)} method in the parser typically creates a default * parser prior to consulting the {@link XMLEventParserContext}, which returns a new parser whose type is determined by * consulting a table of event types. The default parser is returned if the table contains no entry for the event type. *

* A parser can be associated with a specific namespace. The namespace is used to qualify the parser's association with * event types. * * @author tag * @version $Id: AbstractXMLEventParser.java 1981 2014-05-08 03:59:04Z tgaskins $ */ abstract public class AbstractXMLEventParser implements XMLEventParser { protected static final String CHARACTERS_CONTENT = "CharactersContent"; protected String namespaceURI; protected AVList fields; protected XMLEventParser parent; /** Construct a parser with no qualifying namespace. */ public AbstractXMLEventParser() { this.namespaceURI = null; } /** * Constructs a parser and qualifies it for a specified namespace. * * @param namespaceURI the qualifying namespace URI. May be null to indicate no namespace qualification. */ public AbstractXMLEventParser(String namespaceURI) { this.namespaceURI = namespaceURI; } /** * Returns the qualifying namespace URI specified at construction. * * @return the namespace URI. Returns null if no name space was specified at construction. */ public String getNamespaceURI() { return this.namespaceURI; } protected void setNamespaceURI(String namespaceURI) { this.namespaceURI = namespaceURI; } public XMLEventParser newInstance() throws Exception { Constructor constructor = this.getAConstructor(String.class); if (constructor != null) return constructor.newInstance(this.getNamespaceURI()); constructor = this.getAConstructor(); if (constructor != null) return constructor.newInstance(); return null; } public void setField(QName keyName, Object value) { this.setField(keyName.getLocalPart(), value); } public void setField(String keyName, Object value) { if (this.fields == null) this.fields = new AVListImpl(); this.fields.setValue(keyName, value); } public void setFields(Map newFields) { if (this.fields == null) this.fields = new AVListImpl(); for (Map.Entry nf : newFields.entrySet()) { this.setField(nf.getKey(), nf.getValue()); } } public Object getField(QName keyName) { return this.fields != null ? this.getField(keyName.getLocalPart()) : null; } public Object getField(String keyName) { return this.fields != null ? this.fields.getValue(keyName) : null; } public boolean hasField(QName keyName) { return this.hasField(keyName.getLocalPart()); } public boolean hasField(String keyName) { return this.fields != null && this.fields.hasKey(keyName); } public void removeField(String keyName) { if (this.fields != null) this.fields.removeKey(keyName); } public boolean hasFields() { return this.fields != null; } public AVList getFields() { return this.fields; } protected AbstractXMLEventParser mergeFields(AbstractXMLEventParser s1, AbstractXMLEventParser s2) { for (Map.Entry entry : s2.getFields().getEntries()) { if (!s1.hasField(entry.getKey())) s1.setField(entry.getKey(), entry.getValue()); } return this; } protected AbstractXMLEventParser overrideFields(AbstractXMLEventParser s1, AbstractXMLEventParser s2) { if (s2.getFields() != null) { for (Map.Entry entry : s2.getFields().getEntries()) { s1.setField(entry.getKey(), entry.getValue()); } } return this; } public XMLEventParser getParent() { return this.parent; } public void setParent(XMLEventParser parent) { this.parent = parent; } public void freeResources() { // Override in subclass to free any large resources. } protected Constructor getAConstructor(Class... parameterTypes) { try { return this.getClass().getConstructor(parameterTypes); } catch (NoSuchMethodException e) { return null; } } public XMLEventParser getRoot() { XMLEventParser parser = this; while (true) { XMLEventParser parent = parser.getParent(); if (parent == null) return parser; parser = parent; } } /** * Create a parser for a specified event. * * @param ctx the current parser context. * @param event the event for which the parser is created. Only the event type is used; the new parser can operate * on any event of that type. * * @return the new parser. */ public XMLEventParser allocate(XMLEventParserContext ctx, XMLEvent event) { if (ctx == null) { String message = Logging.getMessage("nullValue.ParserContextIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } XMLEventParser parser = ctx.allocate(event); if (parser != null) parser.setParent(this); return parser; } /** {@inheritDoc} */ public Object parse(XMLEventParserContext ctx, XMLEvent inputEvent, Object... args) throws XMLStreamException { if (ctx == null) { String message = Logging.getMessage("nullValue.ParserContextIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (inputEvent == null) { String message = Logging.getMessage("nullValue.EventIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } try { // Parse this event's attributes this.doParseEventAttributes(ctx, inputEvent, args); // Build the symbol table String id = (String) this.getField("id"); if (id != null) ctx.addId(id, this); } catch (XMLStreamException e) { ctx.firePropertyChange(new XMLParserNotification(ctx, XMLParserNotification.EXCEPTION, inputEvent, "XML.ExceptionParsingElement", null, e)); } // Parse the event's subelements. for (XMLEvent event = ctx.nextEvent(); ctx.hasNext(); event = ctx.nextEvent()) { if (event == null) continue; if (ctx.isEndElement(event, inputEvent)) { if (this.hasField(CHARACTERS_CONTENT)) { StringBuilder sb = (StringBuilder) this.getField(CHARACTERS_CONTENT); if (sb != null && sb.length() > 0) this.setField(CHARACTERS_CONTENT, sb.toString()); else this.removeField(CHARACTERS_CONTENT); } return this; } try { if (event.isCharacters()) this.doAddCharacters(ctx, event, args); else this.doParseEventContent(ctx, event, args); } catch (XMLStreamException e) { ctx.firePropertyChange( new XMLParserNotification(ctx, XMLParserNotification.EXCEPTION, event, "XML.ExceptionParsingElement", null, e)); } } return null; } @SuppressWarnings({"UnusedDeclaration"}) protected void doAddCharacters(XMLEventParserContext ctx, XMLEvent event, Object... args) { String s = ctx.getCharacters(event); if (WWUtil.isEmpty(s)) return; StringBuilder sb = (StringBuilder) this.getField(CHARACTERS_CONTENT); if (sb != null) sb.append(s); else this.setField(CHARACTERS_CONTENT, new StringBuilder(s)); } public String getCharacters() { return (String) this.getField(CHARACTERS_CONTENT); } /** * Parse an event's sub-elements. * * @param ctx a current parser context. * @param event the event to parse. * @param args an optional list of arguments that may by used by subclasses. * * @throws XMLStreamException if an exception occurs during event-stream reading. */ protected void doParseEventContent(XMLEventParserContext ctx, XMLEvent event, Object... args) throws XMLStreamException { // Override in subclass to parse an event's sub-elements. if (event.isStartElement()) { XMLEventParser parser = this.allocate(ctx, event); if (parser == null) { ctx.firePropertyChange( new XMLParserNotification(ctx, XMLParserNotification.UNRECOGNIZED, event, "XML.UnrecognizedElement", null, event)); parser = ctx.getUnrecognizedElementParser(); // Register an unrecognized parser for the element type. QName elementName = event.asStartElement().getName(); if (elementName != null) ctx.registerParser(elementName, parser); } if (parser != null) { Object o = parser.parse(ctx, event, args); if (o == null) return; this.doAddEventContent(o, ctx, event, args); } } } protected void doAddEventContent(Object o, XMLEventParserContext ctx, XMLEvent event, Object... args) throws XMLStreamException { // Override in subclass if need to react to certain elements. this.setField(event.asStartElement().getName(), o); } /** * Parse an event's attributes. * * @param ctx a current parser context. * @param event the event to parse. * @param args an optional list of arguments that may by used by subclasses. * * @throws XMLStreamException if an exception occurs during event-stream reading. */ protected void doParseEventAttributes(XMLEventParserContext ctx, XMLEvent event, Object... args) throws XMLStreamException { Iterator iter = event.asStartElement().getAttributes(); if (iter == null) return; while (iter.hasNext()) { this.doAddEventAttribute((Attribute) iter.next(), ctx, event, args); } } protected void doAddEventAttribute(Attribute attr, XMLEventParserContext ctx, XMLEvent event, Object... args) throws XMLStreamException { // Override in subclass if need to react to certain attributes. this.setField(attr.getName(), attr.getValue()); } @SuppressWarnings({"UnusedDeclaration"}) protected String parseCharacterContent(XMLEventParserContext ctx, XMLEvent stringEvent, Object... args) throws XMLStreamException { StringBuilder value = new StringBuilder(); for (XMLEvent event = ctx.nextEvent(); event != null; event = ctx.nextEvent()) { if (ctx.isEndElement(event, stringEvent)) return value.length() > 0 ? value.toString() : null; if (event.isCharacters()) { String s = ctx.getCharacters(event); if (s != null) value.append(s); } } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy