/******************************************************************************* * Copyright (c) 2004, 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 eu.esdihumboldt.hale.util.nonosgi.contenttype.describer; import java.io.IOException; import java.io.StringReader; import javax.xml.parsers.*; import org.eclipse.core.internal.content.Activator; import org.xml.sax.*; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.DefaultHandler; /** * A content describer for detecting the name of the top-level element of the * DTD system identifier in an XML file. This supports two parameters: * <code>DTD_TO_FIND</code> and <code>ELEMENT_TO_FIND</code>. This is done * using the <code>IExecutableExtension</code> mechanism. If the * <code>":-"</code> method is used, then the value is treated as the * <code>ELEMENT_TO_FIND</code>. * * @since 3.0 */ @SuppressWarnings("restriction") public final class XMLRootHandler extends DefaultHandler implements LexicalHandler { /** * An exception indicating that the parsing should stop. This is usually * triggered when the top-level element has been found. * * @since 3.0 */ private class StopParsingException extends SAXException { /** * All serializable objects should have a stable serialVersionUID */ private static final long serialVersionUID = 1L; /** * Constructs an instance of <code>StopParsingException</code> with a * <code>null</code> detail message. */ public StopParsingException() { super((String) null); } } /** * Should we check the root element? */ private boolean checkRoot; /** * The system identifier for the DTD that was found while parsing the XML. * This member variable is <code>null</code> unless the file has been * parsed successful to the point of finding the DTD's system identifier. */ private String dtdFound = null; /** * This is the name of the top-level element found in the XML file. This * member variable is <code>null</code> unless the file has been parsed * successful to the point of finding the top-level element. */ private String elementFound = null; /** * This is the namespace of the top-level element found in the XML file. This * member variable is <code>null</code> unless the file has been parsed * successful to the point of finding the top-level element. */ private String namespaceFound = null; public XMLRootHandler(boolean checkRoot) { this.checkRoot = checkRoot; } /* * (non-Javadoc) * * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int) */ public final void comment(final char[] ch, final int start, final int length) { // Not interested. } /** * Creates a new SAX parser for use within this instance. * * @return The newly created parser. * * @throws ParserConfigurationException * If a parser of the given configuration cannot be created. * @throws SAXException * If something in general goes wrong when creating the parser. * @throws SAXNotRecognizedException * If the <code>XMLReader</code> does not recognize the * lexical handler configuration option. * @throws SAXNotSupportedException * If the <code>XMLReader</code> does not support the lexical * handler configuration option. */ private final SAXParser createParser(SAXParserFactory parserFactory) throws ParserConfigurationException, SAXException, SAXNotRecognizedException, SAXNotSupportedException { // Initialize the parser. final SAXParser parser = parserFactory.newSAXParser(); final XMLReader reader = parser.getXMLReader(); reader.setProperty("http://xml.org/sax/properties/lexical-handler", this); //$NON-NLS-1$ // disable DTD validation (bug 63625) try { // be sure validation is "off" or the feature to ignore DTD's will not apply reader.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$ } catch (SAXNotRecognizedException e) { // not a big deal if the parser does not recognize the features } catch (SAXNotSupportedException e) { // not a big deal if the parser does not support the features } return parser; } /* * (non-Javadoc) * * @see org.xml.sax.ext.LexicalHandler#endCDATA() */ public final void endCDATA() { // Not interested. } /* * (non-Javadoc) * * @see org.xml.sax.ext.LexicalHandler#endDTD() */ public final void endDTD() { // Not interested. } /* * (non-Javadoc) * * @see org.xml.sax.ext.LexicalHandler#endEntity(java.lang.String) */ public final void endEntity(final String name) { // Not interested. } public String getDTD() { return dtdFound; } public String getRootName() { return elementFound; } /** * @since org.eclipse.core.contenttype 3.3 */ public String getRootNamespace() { return namespaceFound; } public boolean parseContents(InputSource contents) throws IOException, ParserConfigurationException, SAXException { // Parse the file into we have what we need (or an error occurs). try { SAXParserFactory factory = null; if (Activator.getDefault() != null) { factory = Activator.getDefault().getFactory(); } if (factory == null) { // if no factory is available via OSGi, try creating one factory = SAXParserFactory.newInstance(); } final SAXParser parser = createParser(factory); // to support external entities specified as relative URIs (see bug 63298) contents.setSystemId("/"); //$NON-NLS-1$ parser.parse(contents, this); } catch (StopParsingException e) { // Abort the parsing normally. Fall through... } return true; } /* * Resolve external entity definitions to an empty string. This is to speed * up processing of files with external DTDs. Not resolving the contents * of the DTD is ok, as only the System ID of the DTD declaration is used. * @see org.xml.sax.helpers.DefaultHandler#resolveEntity(java.lang.String, java.lang.String) */ public InputSource resolveEntity(String publicId, String systemId) throws SAXException { return new InputSource(new StringReader("")); //$NON-NLS-1$ } /* * (non-Javadoc) * * @see org.xml.sax.ext.LexicalHandler#startCDATA() */ public final void startCDATA() { // Not interested. } /* * (non-Javadoc) * * @see org.xml.sax.ext.LexicalHandler#startDTD(java.lang.String, * java.lang.String, java.lang.String) */ public final void startDTD(final String name, final String publicId, final String systemId) throws SAXException { dtdFound = systemId; // If we don't care about the top-level element, we can stop here. if (!checkRoot) throw new StopParsingException(); } /* * (non-Javadoc) * * @see org.xml.sax.ContentHandler#startElement(java.lang.String, * java.lang.String, java.lang.String, org.xml.sax.Attributes) */ public final void startElement(final String uri, final String elementName, final String qualifiedName, final Attributes attributes) throws SAXException { elementFound = elementName; namespaceFound = uri; throw new StopParsingException(); } /* * (non-Javadoc) * * @see org.xml.sax.ext.LexicalHandler#startEntity(java.lang.String) */ public final void startEntity(final String name) { // Not interested. } }