/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php * * 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 com.android.ide.eclipse.editors; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; /** * Quickly parses a (potential) XML file to extract its first element (i.e. the root element) * and namespace, if any. * <p/> * This is used to determine if a file is an XML document that the XmlEditor can process. * <p/> * TODO use this to remove the hardcoded "android" namespace prefix limitation. */ public final class FirstElementParser { private static SAXParserFactory sSaxfactory; /** * Result from the XML parsing. <br/> * Contains the name of the root XML element. <br/> * If an XMLNS URI was specified and found, the XMLNS prefix is recorded. Otherwise it is null. */ public static final class Result { private String mElement; private String mXmlnsPrefix; private String mXmlnsUri; public String getElement() { return mElement; } public String getXmlnsPrefix() { return mXmlnsPrefix; } public String getXmlnsUri() { return mXmlnsUri; } void setElement(String element) { mElement = element; } void setXmlnsPrefix(String xmlnsPrefix) { mXmlnsPrefix = xmlnsPrefix; } void setXmlnsUri(String xmlnsUri) { mXmlnsUri = xmlnsUri; } } private static class ResultFoundException extends SAXException { } /** * Parses the given filename. * * @param osFilename The file to parse. * @param xmlnsUri An optional URL of which we want to know the prefix. * @return The element details found or null if not found. */ public static Result parse(String osFilename, String xmlnsUri) { if (sSaxfactory == null) { // TODO just create a single factory in CommonPlugin and reuse it sSaxfactory = SAXParserFactory.newInstance(); sSaxfactory.setNamespaceAware(true); } Result result = new Result(); if (xmlnsUri != null && xmlnsUri.length() > 0) { result.setXmlnsUri(xmlnsUri); } try { SAXParser parser = sSaxfactory.newSAXParser(); XmlHandler handler = new XmlHandler(result); parser.parse(new InputSource(new FileReader(osFilename)), handler); } catch(ResultFoundException e) { // XML handling was aborted because the required element was found. // Simply return the result. return result; } catch (ParserConfigurationException e) { } catch (SAXException e) { } catch (FileNotFoundException e) { } catch (IOException e) { } return null; } /** * Private constructor. Use the static parse() method instead. */ private FirstElementParser() { // pass } /** * A specialized SAX handler that captures the arguments of the very first element * (i.e. the root element) */ private static class XmlHandler extends DefaultHandler { private final Result mResult; public XmlHandler(Result result) { mResult = result; } /** * Processes a namespace prefix mapping. * I.e. for xmlns:android="some-uri", this received prefix="android" and uri="some-uri". * <p/> * The prefix is recorded in the result structure if the URI is the one searched for. * <p/> * This event happens <em>before</em> the corresponding startElement event. */ @Override public void startPrefixMapping(String prefix, String uri) { if (uri.equals(mResult.getXmlnsUri())) { mResult.setXmlnsPrefix(prefix); } } /** * Processes a new element start. * <p/> * This simply records the element name and abort processing by throwing an exception. */ @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { mResult.setElement(localName); throw new ResultFoundException(); } } }