Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLParser.java')
-rw-r--r--bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLParser.java765
1 files changed, 765 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLParser.java b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLParser.java
new file mode 100644
index 000000000..d96221e40
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLParser.java
@@ -0,0 +1,765 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.persistence;
+
+import java.net.*;
+import java.util.List;
+import java.util.StringTokenizer;
+import javax.xml.parsers.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.equinox.internal.p2.core.Activator;
+import org.eclipse.equinox.internal.p2.core.StringPool;
+import org.eclipse.equinox.internal.p2.core.helpers.OrderedProperties;
+import org.eclipse.equinox.internal.p2.core.helpers.Tracing;
+import org.eclipse.equinox.internal.provisional.p2.core.Version;
+import org.eclipse.equinox.internal.provisional.p2.core.VersionRange;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+import org.xml.sax.*;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.helpers.DefaultHandler;
+
+public abstract class XMLParser extends DefaultHandler implements XMLConstants {
+
+ // Get the root object that is being parsed.
+ protected abstract Object getRootObject();
+
+ // Get a generic parser error message for inclusion in an error status
+ protected abstract String getErrorMessage();
+
+ protected BundleContext context; // parser class bundle context
+ protected String bundleId; // parser class bundle id
+
+ protected XMLReader xmlReader; // the XML reader for the parser
+
+ protected MultiStatus status = null; // accumulation of non-fatal errors
+ protected Locator locator = null; // document locator, if supported by the parser
+
+ protected StringPool stringPool = new StringPool();//used to eliminate string duplication
+ private IProgressMonitor monitor;
+
+ private static ServiceTracker xmlTracker = null;
+
+ public XMLParser(BundleContext context, String pluginId) {
+ super();
+ this.context = context;
+ this.bundleId = pluginId;
+ }
+
+ /**
+ * Non-fatal errors accumulated during parsing.
+ */
+ public IStatus getStatus() {
+ return (status != null ? status : Status.OK_STATUS);
+ }
+
+ /**
+ * Returns the canonical form of a string. Used to eliminate duplicate equal
+ * strings.
+ */
+ protected String canonicalize(String string) {
+ return stringPool == null ? string : stringPool.add(string);
+ }
+
+ public boolean isValidXML() {
+ return (status == null || !status.matches(IStatus.ERROR | IStatus.CANCEL));
+ }
+
+ private static SAXParserFactory acquireXMLParsing(BundleContext context) {
+ if (xmlTracker == null) {
+ xmlTracker = new ServiceTracker(context, SAXParserFactory.class.getName(), null);
+ xmlTracker.open();
+ }
+ return (SAXParserFactory) xmlTracker.getService();
+ }
+
+ protected static void releaseXMLParsing() {
+ if (xmlTracker != null) {
+ xmlTracker.close();
+ }
+ }
+
+ protected SAXParser getParser() throws ParserConfigurationException, SAXException {
+ SAXParserFactory factory = acquireXMLParsing(this.context);
+ if (factory == null) {
+ throw new SAXException(Messages.XMLParser_No_SAX_Parser);
+ }
+ factory.setNamespaceAware(true);
+ factory.setValidating(false);
+ try {
+ factory.setFeature("http://xml.org/sax/features/string-interning", true); //$NON-NLS-1$
+ } catch (SAXException se) {
+ // some parsers may not support string interning
+ }
+ SAXParser theParser = factory.newSAXParser();
+ if (theParser == null) {
+ throw new SAXException(Messages.XMLParser_No_SAX_Parser);
+ }
+ xmlReader = theParser.getXMLReader();
+ return theParser;
+ }
+
+ public static String makeSimpleName(String localName, String qualifiedName) {
+ if (localName != null && localName.length() > 0) {
+ return localName;
+ }
+ int nameSpaceIndex = qualifiedName.indexOf(":"); //$NON-NLS-1$
+ return (nameSpaceIndex == -1 ? qualifiedName : qualifiedName.substring(nameSpaceIndex + 1));
+ }
+
+ /**
+ * Set the document locator for the parser
+ *
+ * @see org.xml.sax.ContentHandler#setDocumentLocator
+ */
+ public void setDocumentLocator(Locator docLocator) {
+ locator = docLocator;
+ }
+
+ /**
+ * Sets the progress monitor for the parser
+ */
+ protected void setProgressMonitor(IProgressMonitor monitor) {
+ this.monitor = monitor;
+ }
+
+ /**
+ * Abstract base class for content handlers
+ */
+ protected abstract class AbstractHandler extends DefaultHandler {
+
+ protected ContentHandler parentHandler = null;
+ protected String elementHandled = null;
+
+ protected StringBuffer characters = null; // character data inside an element
+
+ public AbstractHandler() {
+ // Empty constructor for a root handler
+ }
+
+ public AbstractHandler(ContentHandler parentHandler) {
+ this.parentHandler = parentHandler;
+ xmlReader.setContentHandler(this);
+ }
+
+ public AbstractHandler(ContentHandler parentHandler, String elementHandled) {
+ this.parentHandler = parentHandler;
+ xmlReader.setContentHandler(this);
+ this.elementHandled = elementHandled;
+ }
+
+ /**
+ * Set the document locator for the parser
+ *
+ * @see org.xml.sax.ContentHandler#setDocumentLocator
+ */
+ public void setDocumentLocator(Locator docLocator) {
+ locator = docLocator;
+ }
+
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ finishCharacters();
+ String name = makeSimpleName(localName, qName);
+ trace(name, attributes);
+ startElement(name, attributes);
+ }
+
+ public abstract void startElement(String name, Attributes attributes) throws SAXException;
+
+ public void invalidElement(String name, Attributes attributes) {
+ unexpectedElement(this, name, attributes);
+ new IgnoringHandler(this);
+ }
+
+ public void endElement(String namespaceURI, String localName, String qName) {
+ // TODO: throw a bad state error if makeSimpleName(localName, qName) != elementHandled
+ finishCharacters();
+ finished();
+ // Restore the parent content handler
+ xmlReader.setContentHandler(parentHandler);
+ }
+
+ /**
+ * An implementation for startElement when there are no sub-elements
+ */
+ protected void noSubElements(String name, Attributes attributes) {
+ unexpectedElement(this, name, attributes);
+ // Create a new handler to ignore subsequent nested elements
+ new IgnoringHandler(this);
+ }
+
+ /*
+ * Save up character data until endElement or nested startElement
+ *
+ * @see org.xml.sax.ContentHandler#characters
+ */
+ public void characters(char[] chars, int start, int length) {
+ if (this.characters == null) {
+ this.characters = new StringBuffer();
+ }
+ this.characters.append(chars, start, length);
+ }
+
+ // Consume the characters accumulated in this.characters.
+ // Called before startElement or endElement
+ private String finishCharacters() {
+ // common case -- no characters or only whitespace
+ if (this.characters == null || this.characters.length() == 0) {
+ return null;
+ }
+ if (allWhiteSpace(this.characters)) {
+ this.characters.setLength(0);
+ return null;
+ }
+
+ // process the characters
+ try {
+ String trimmedChars = this.characters.toString().trim();
+ if (trimmedChars.length() == 0) {
+ // this shouldn't happen due to the test for allWhiteSpace above
+ System.err.println("Unexpected non-whitespace characters: " //$NON-NLS-1$
+ + trimmedChars);
+ return null;
+ }
+ processCharacters(trimmedChars);
+ return trimmedChars;
+ } finally {
+ this.characters.setLength(0);
+ }
+ }
+
+ // Method to override in the handler of an element with CDATA.
+ protected void processCharacters(String data) {
+ if (data.length() > 0) {
+ unexpectedCharacterData(this, data);
+ }
+ }
+
+ private boolean allWhiteSpace(StringBuffer sb) {
+ int length = sb.length();
+ for (int i = 0; i < length; i += 1) {
+ if (!Character.isWhitespace(sb.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Called when this element and all elements nested into it have been
+ * handled.
+ */
+ protected void finished() {
+ // Do nothing by default
+ }
+
+ /*
+ * A name used to identify the handler.
+ */
+ public String getName() {
+ return (elementHandled != null ? elementHandled : "NoName"); //$NON-NLS-1$
+ }
+
+ /**
+ * In p2 1.0 we stored URLs, in 1.1 and later we store URIs. This method will
+ * first check for a URI, and then resort to looking for a URL attribute for
+ * backwards compatibility.
+ * @param attributes The attributes to parse
+ * @param required If true, an exception is thrown if no URI or URL attribute is present
+ */
+ protected URI parseURIAttribute(Attributes attributes, boolean required) {
+ String location = parseOptionalAttribute(attributes, URI_ATTRIBUTE);
+ try {
+ if (location != null)
+ return new URI(location);
+ if (required)
+ location = parseRequiredAttributes(attributes, new String[] {URL_ATTRIBUTE})[0];
+ else
+ location = parseOptionalAttribute(attributes, URL_ATTRIBUTE);
+ if (location == null)
+ return null;
+ return URIUtil.toURI(new URL(location));
+ } catch (MalformedURLException e) {
+ invalidAttributeValue(elementHandled, URL_ATTRIBUTE, location, e);
+ } catch (URISyntaxException e) {
+ invalidAttributeValue(elementHandled, URL_ATTRIBUTE, location, e);
+ }
+ return null;
+ }
+
+ /**
+ * Parse the attributes of an element with two required attributes.
+ */
+ protected String[] parseRequiredAttributes(Attributes attributes, String name1, String name2) {
+ return parseRequiredAttributes(attributes, new String[] {name1, name2});
+ }
+
+ /**
+ * Parse the attributes of an element with only required attributes.
+ */
+ protected String[] parseRequiredAttributes(Attributes attributes, String[] required) {
+ return parseAttributes(attributes, required, noAttributes);
+ }
+
+ /**
+ * Parse the attributes of an element with a single optional attribute.
+ */
+ protected String parseOptionalAttribute(Attributes attributes, String name) {
+ return parseAttributes(attributes, noAttributes, new String[] {name})[0];
+ }
+
+ /**
+ * Parse the attributes of an element, given the list of required and optional ones.
+ * Return values in same order, null for those not present.
+ * Log warnings for extra attributes or missing required attributes.
+ */
+ protected String[] parseAttributes(Attributes attributes, String[] required, String[] optional) {
+ String[] result = new String[required.length + optional.length];
+ for (int i = 0; i < attributes.getLength(); i += 1) {
+ String name = attributes.getLocalName(i);
+ String value = canonicalize(attributes.getValue(i).trim());
+ int j;
+ if ((j = indexOf(required, name)) >= 0) {
+ result[j] = value;
+ } else if ((j = indexOf(optional, name)) >= 0) {
+ result[required.length + j] = value;
+ } else {
+ unexpectedAttribute(elementHandled, name, value);
+ }
+ }
+ for (int i = 0; i < required.length; i += 1) {
+ checkRequiredAttribute(elementHandled, required[i], result[i]);
+ }
+ return result;
+ }
+
+ }
+
+ /**
+ * Handler for an XML document.
+ *
+ * Using the inelegant name 'DocHandler' to clearly distinguish
+ * this class from the deprecated org.xml.sax.DocumentHandler.
+ */
+ protected class DocHandler extends AbstractHandler {
+
+ RootHandler rootHandler;
+
+ public DocHandler(String rootName, RootHandler rootHandler) {
+ super(null, rootName);
+ this.rootHandler = rootHandler;
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equals(elementHandled)) {
+ rootHandler.initialize(this, name, attributes);
+ xmlReader.setContentHandler(rootHandler);
+ } else {
+ this.noSubElements(name, attributes);
+ }
+ }
+
+ }
+
+ /**
+ * Abstract handler for the root element.
+ */
+ protected abstract class RootHandler extends AbstractHandler {
+
+ public RootHandler() {
+ super();
+ }
+
+ public void initialize(DocHandler document, String rootName, Attributes attributes) {
+ this.parentHandler = document;
+ this.elementHandled = rootName;
+ handleRootAttributes(attributes);
+ }
+
+ protected abstract void handleRootAttributes(Attributes attributes);
+
+ }
+
+ /**
+ * Handler for an ordered properties collection.
+ */
+ protected class PropertiesHandler extends AbstractHandler {
+
+ private OrderedProperties properties;
+
+ public PropertiesHandler(ContentHandler parentHandler, Attributes attributes) {
+ super(parentHandler, PROPERTIES_ELEMENT);
+ String size = parseOptionalAttribute(attributes, COLLECTION_SIZE_ATTRIBUTE);
+ properties = (size != null ? new OrderedProperties(new Integer(size).intValue()) : new OrderedProperties());
+ }
+
+ public OrderedProperties getProperties() {
+ return properties;
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ if (name.equals(PROPERTY_ELEMENT)) {
+ new PropertyHandler(this, attributes, properties);
+ } else {
+ invalidElement(name, attributes);
+ }
+ }
+
+ }
+
+ /**
+ * Handler for a property in an ordered properties collection.
+ */
+ protected class PropertyHandler extends AbstractHandler {
+
+ public PropertyHandler(ContentHandler parentHandler, Attributes attributes, OrderedProperties properties) {
+ super(parentHandler, PROPERTY_ELEMENT);
+ String[] property = parseProperty(attributes);
+ if (isValidProperty(property)) {
+ properties.setProperty(property[0], property[1]);
+ }
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ invalidElement(name, attributes);
+ }
+
+ private String[] parseProperty(Attributes attributes) {
+ return parseRequiredAttributes(attributes, PROPERTY_NAME_ATTRIBUTE, PROPERTY_VALUE_ATTRIBUTE);
+ }
+
+ private boolean isValidProperty(String[] property) {
+ return (property.length == 2 && property[0] != null && property[1] != null);
+ }
+ }
+
+ /**
+ * Handler for an element with only cdata and no sub-elements.
+ */
+ protected class TextHandler extends AbstractHandler {
+
+ private String text = null;
+
+ private List texts = null;
+
+ // Constructor for a subclass that processes the attributes
+ public TextHandler(AbstractHandler parent, String elementName) {
+ super(parent, elementName);
+ }
+
+ // Constructor for a subclass with no attributes
+ public TextHandler(AbstractHandler parent, String elementName, Attributes attributes) {
+ super(parent, elementName);
+ parseAttributes(attributes, noAttributes, noAttributes);
+ }
+
+ public TextHandler(AbstractHandler parent, String elementName, Attributes attributes, List texts) {
+ super(parent, elementName);
+ parseAttributes(attributes, noAttributes, noAttributes);
+ this.texts = texts;
+ }
+
+ public String getText() {
+ return (text != null ? text : ""); //$NON-NLS-1$
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ invalidElement(name, attributes);
+ }
+
+ protected void processCharacters(String data) {
+ this.text = canonicalize(data);
+ if (texts != null) {
+ texts.add(getText());
+ }
+ }
+
+ }
+
+ /**
+ * Handler for ignoring content.
+ */
+ protected class IgnoringHandler extends AbstractHandler {
+
+ public IgnoringHandler(AbstractHandler parent) {
+ super(parent);
+ this.elementHandled = "IgnoringAll"; //$NON-NLS-1$
+ }
+
+ public void startElement(String name, Attributes attributes) {
+ noSubElements(name, attributes);
+ }
+
+ }
+
+ // Helper for processing instructions that include a Version.
+ public Version extractPIVersion(String target, String data) {
+ return checkVersion(target, PI_VERSION_ATTRIBUTE, extractPIAttribute(data, PI_VERSION_ATTRIBUTE));
+ }
+
+ private String extractPIAttribute(String data, String key) {
+ StringTokenizer piTokenizer = new StringTokenizer(data, " \'\""); //$NON-NLS-1$
+ String[] tokens = new String[piTokenizer.countTokens()];
+ int index = 0;
+ int valueIndex = -1;
+ while (piTokenizer.hasMoreTokens() && index < tokens.length) {
+ tokens[index] = piTokenizer.nextToken();
+ if (tokens[index].equals(key + '=') && index < tokens.length) {
+ valueIndex = index + 1;
+ }
+ index++;
+ }
+ return (valueIndex >= 0 ? tokens[valueIndex] : ""); //$NON-NLS-1$
+ }
+
+ public void error(SAXParseException ex) {
+ addError(IStatus.WARNING, ex.getMessage(), ex);
+ }
+
+ public void fatalError(SAXParseException ex) {
+ addError(IStatus.ERROR, ex.getMessage(), ex);
+ }
+
+ protected String getErrorPrefix() {
+ return null;
+ }
+
+ protected String getErrorSuffix() {
+ return null;
+ }
+
+ /**
+ * Collects an error or warning that occurred during parsing.
+ */
+ public final void addError(int severity, String msg, Throwable exception) {
+ int line = 0;
+ int column = 0;
+ String key = msg;
+ Object[] args = new Object[] {};
+ String root = (getRootObject() == null ? "" //$NON-NLS-1$
+ : " (" + getRootObject() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (this.locator != null) {
+ String name = this.locator.getSystemId();
+ line = this.locator.getLineNumber();
+ column = this.locator.getColumnNumber();
+ if (line > 0) {
+ args = new Object[] {msg, root, name, new Integer(line), new Integer(column)};
+ if (column > 0) {
+ key = (name != null ? Messages.XMLParser_Error_At_Name_Line_Column //
+ : Messages.XMLParser_Error_At_Line_Column);
+ } else {
+ key = (name != null ? Messages.XMLParser_Error_At_Name_Line //
+ : Messages.XMLParser_Error_At_Line);
+ }
+ }
+ }
+ String errMsg = NLS.bind(key, args);
+ String prefix = getErrorPrefix();
+ String suffix = getErrorSuffix();
+ if (prefix != null) {
+ errMsg = prefix + errMsg;
+ }
+ if (suffix != null) {
+ errMsg = errMsg + suffix;
+ }
+ IStatus currStatus = new Status(severity, Activator.ID, errMsg, exception);
+ if (this.status == null) {
+ this.status = new MultiStatus(bundleId, IStatus.OK, new IStatus[] {currStatus}, getErrorMessage(), null);
+ } else {
+ this.status.add(currStatus);
+ }
+ }
+
+ public void trace(String element, Attributes attributes) {
+ // TODO: support logging
+ // if (!getLogger().isDebugLoggable()) {
+ // return;
+ // }
+ // int indentSize = (this.stateStack != null ? this.stateStack.size() - 1 : 1);
+ // if (attributes == null) {
+ // indentSize -= 1;
+ // }
+ // char[] indent = new char[2 * indentSize];
+ // Arrays.fill(indent, ' ');
+ // StringBuffer sb = new StringBuffer();
+ // sb.append(indent);
+ // sb.append('<');
+ // if (attributes != null) {
+ // sb.append(element);
+ // toString(sb, attributes);
+ // } else {
+ // sb.append('/').append(element);
+ // }
+ // sb.append('>');
+ // getLogger().debug(sb.toString());
+ }
+
+ private static String toString(Attributes attributes) {
+ StringBuffer result = new StringBuffer();
+ toString(result, attributes);
+ return result.toString();
+ }
+
+ private static void toString(StringBuffer sb, Attributes attributes) {
+ for (int i = 0; i < attributes.getLength(); i += 1) {
+ String name = attributes.getLocalName(i);
+ String value = attributes.getValue(i).trim();
+ sb.append(' ').append(name);
+ sb.append('=').append('"');
+ sb.append(value);
+ sb.append('"');
+ }
+ }
+
+ public void checkRequiredAttribute(String element, String name, Object value) {
+ if (value == null) {
+ addError(IStatus.WARNING, NLS.bind(Messages.XMLParser_Missing_Required_Attribute, element, name), null);
+ }
+ }
+
+ // Check the format of a required boolean attribute
+ public Boolean checkBoolean(String element, String attribute, String value) {
+ try {
+ return Boolean.valueOf(value);
+ } catch (IllegalArgumentException iae) {
+ invalidAttributeValue(element, attribute, value);
+ } catch (NullPointerException npe) {
+ invalidAttributeValue(element, attribute, null);
+ }
+ return Boolean.FALSE;
+ }
+
+ // Check the format of an optional boolean attribute
+ public Boolean checkBoolean(String element, String attribute, String value, boolean defaultValue) {
+ Boolean result = (defaultValue ? Boolean.TRUE : Boolean.FALSE);
+ if (value != null) {
+ try {
+ return Boolean.valueOf(value);
+ } catch (IllegalArgumentException iae) {
+ invalidAttributeValue(element, attribute, value);
+ }
+ }
+ return result;
+ }
+
+ // Check the format of a required integer attribute
+ public int checkInteger(String element, String attribute, String value) {
+ try {
+ return Integer.parseInt(value);
+ } catch (IllegalArgumentException iae) {
+ invalidAttributeValue(element, attribute, value);
+ }
+ return 0;
+ }
+
+ // Check the format of a required URI attribute
+ public URI checkURI(String element, String attribute, String value) {
+ try {
+ return URIUtil.fromString(value);
+ } catch (URISyntaxException e) {
+ invalidAttributeValue(element, attribute, value);
+ }
+ //TODO ok to return null?
+ return null;
+ }
+
+ public void checkCancel() {
+ if (monitor != null && monitor.isCanceled())
+ throw new OperationCanceledException();
+ }
+
+ /**
+ * Converts a version string to a Version object. Returns the version object,
+ * or {@link Version#emptyVersion} if the value was not a valid version.
+ */
+ public Version checkVersion(String element, String attribute, String value) {
+ try {
+ if (value != null)
+ return new Version(value);
+ } catch (IllegalArgumentException iae) {
+ invalidAttributeValue(element, attribute, value);
+ } catch (NullPointerException npe) {
+ invalidAttributeValue(element, attribute, null);
+ }
+ return Version.emptyVersion;
+ }
+
+ public VersionRange checkVersionRange(String element, String attribute, String value) {
+ try {
+ return new VersionRange(value);
+ } catch (IllegalArgumentException iae) {
+ invalidAttributeValue(element, attribute, value);
+ } catch (NullPointerException npe) {
+ invalidAttributeValue(element, attribute, null);
+ }
+ return VersionRange.emptyRange;
+ }
+
+ public void unexpectedAttribute(String element, String attribute, String value) {
+ if (Tracing.DEBUG_PARSE_PROBLEMS)
+ Tracing.debug("Unexpected attribute for element " + element + ": " + attribute + '=' + value); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public void invalidAttributeValue(String element, String attribute, String value) {
+ invalidAttributeValue(element, attribute, value, null);
+ }
+
+ public void invalidAttributeValue(String element, String attribute, String value, Throwable exception) {
+ addError(IStatus.WARNING, NLS.bind(Messages.XMLParser_Illegal_Value_For_Attribute, new Object[] {attribute, element, value}), exception);
+ }
+
+ public void unexpectedElement(AbstractHandler handler, String element, Attributes attributes) {
+ if (Tracing.DEBUG_PARSE_PROBLEMS)
+ Tracing.debug("Unexpected element in element " + handler.getName() + ": <" + element + toString(attributes) + '>'); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public void duplicateElement(AbstractHandler handler, String element, Attributes attributes) {
+ addError(IStatus.WARNING, NLS.bind(Messages.XMLParser_Duplicate_Element, new Object[] {handler.getName(), element, toString(attributes)}), null);
+ //ignore the duplicate element entirely because we have already logged it
+ new IgnoringHandler(handler);
+ }
+
+ public void unexpectedCharacterData(AbstractHandler handler, String cdata) {
+ if (Tracing.DEBUG_PARSE_PROBLEMS)
+ Tracing.debug("Unexpected character data in element " + handler.getName() + ": " + cdata.trim()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Find the index of the first occurrence of object in array, or -1.
+ * Use Arrays.binarySearch if array is big and sorted.
+ */
+ protected static int indexOf(String[] array, String value) {
+ for (int i = 0; i < array.length; i += 1) {
+ if (value == null ? array[i] == null : value.equals(array[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ // public class BadStateError extends AssertionError {
+ // private static final long serialVersionUID = 1L; // not serialized
+ //
+ // public BadStateError() {
+ // super("unexpected state" + //$NON-NLS-1$
+ // (XMLParser.this.stateStack != null ? ": " + XMLParser.this.stateStack //$NON-NLS-1$
+ // : "")); //$NON-NLS-1$
+ // }
+ //
+ // public BadStateError(String element) {
+ // super("unexpected state for " + element + //$NON-NLS-1$
+ // (XMLParser.this.stateStack != null ? ": " + XMLParser.this.stateStack //$NON-NLS-1$
+ // : "")); //$NON-NLS-1$
+ // }
+ // }
+
+}

Back to the top