|  | /* | 
|  | * Copyright (C) 2007 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * 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 android.sax; | 
|  |  | 
|  | import org.xml.sax.Locator; | 
|  | import org.xml.sax.SAXParseException; | 
|  |  | 
|  | import java.util.ArrayList; | 
|  |  | 
|  | /** | 
|  | * An XML element. Provides access to child elements and hooks to listen | 
|  | * for events related to this element. | 
|  | * | 
|  | * @see RootElement | 
|  | */ | 
|  | public class Element { | 
|  |  | 
|  | final String uri; | 
|  | final String localName; | 
|  | final int depth; | 
|  | final Element parent; | 
|  |  | 
|  | Children children; | 
|  | ArrayList<Element> requiredChilden; | 
|  |  | 
|  | boolean visited; | 
|  |  | 
|  | StartElementListener startElementListener; | 
|  | EndElementListener endElementListener; | 
|  | EndTextElementListener endTextElementListener; | 
|  |  | 
|  | Element(Element parent, String uri, String localName, int depth) { | 
|  | this.parent = parent; | 
|  | this.uri = uri; | 
|  | this.localName = localName; | 
|  | this.depth = depth; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the child element with the given name. Uses an empty string as the | 
|  | * namespace. | 
|  | */ | 
|  | public Element getChild(String localName) { | 
|  | return getChild("", localName); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the child element with the given name. | 
|  | */ | 
|  | public Element getChild(String uri, String localName) { | 
|  | if (endTextElementListener != null) { | 
|  | throw new IllegalStateException("This element already has an end" | 
|  | + " text element listener. It cannot have children."); | 
|  | } | 
|  |  | 
|  | if (children == null) { | 
|  | children = new Children(); | 
|  | } | 
|  |  | 
|  | return children.getOrCreate(this, uri, localName); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the child element with the given name. Uses an empty string as the | 
|  | * namespace. We will throw a {@link org.xml.sax.SAXException} at parsing | 
|  | * time if the specified child is missing. This helps you ensure that your | 
|  | * listeners are called. | 
|  | */ | 
|  | public Element requireChild(String localName) { | 
|  | return requireChild("", localName); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the child element with the given name. We will throw a | 
|  | * {@link org.xml.sax.SAXException} at parsing time if the specified child | 
|  | * is missing. This helps you ensure that your listeners are called. | 
|  | */ | 
|  | public Element requireChild(String uri, String localName) { | 
|  | Element child = getChild(uri, localName); | 
|  |  | 
|  | if (requiredChilden == null) { | 
|  | requiredChilden = new ArrayList<Element>(); | 
|  | requiredChilden.add(child); | 
|  | } else { | 
|  | if (!requiredChilden.contains(child)) { | 
|  | requiredChilden.add(child); | 
|  | } | 
|  | } | 
|  |  | 
|  | return child; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets start and end element listeners at the same time. | 
|  | */ | 
|  | public void setElementListener(ElementListener elementListener) { | 
|  | setStartElementListener(elementListener); | 
|  | setEndElementListener(elementListener); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets start and end text element listeners at the same time. | 
|  | */ | 
|  | public void setTextElementListener(TextElementListener elementListener) { | 
|  | setStartElementListener(elementListener); | 
|  | setEndTextElementListener(elementListener); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets a listener for the start of this element. | 
|  | */ | 
|  | public void setStartElementListener( | 
|  | StartElementListener startElementListener) { | 
|  | if (this.startElementListener != null) { | 
|  | throw new IllegalStateException( | 
|  | "Start element listener has already been set."); | 
|  | } | 
|  | this.startElementListener = startElementListener; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets a listener for the end of this element. | 
|  | */ | 
|  | public void setEndElementListener(EndElementListener endElementListener) { | 
|  | if (this.endElementListener != null) { | 
|  | throw new IllegalStateException( | 
|  | "End element listener has already been set."); | 
|  | } | 
|  | this.endElementListener = endElementListener; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets a listener for the end of this text element. | 
|  | */ | 
|  | public void setEndTextElementListener( | 
|  | EndTextElementListener endTextElementListener) { | 
|  | if (this.endTextElementListener != null) { | 
|  | throw new IllegalStateException( | 
|  | "End text element listener has already been set."); | 
|  | } | 
|  |  | 
|  | if (children != null) { | 
|  | throw new IllegalStateException("This element already has children." | 
|  | + " It cannot have an end text element listener."); | 
|  | } | 
|  |  | 
|  | this.endTextElementListener = endTextElementListener; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toString() { | 
|  | return toString(uri, localName); | 
|  | } | 
|  |  | 
|  | static String toString(String uri, String localName) { | 
|  | return "'" + (uri.equals("") ? localName : uri + ":" + localName) + "'"; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Clears flags on required children. | 
|  | */ | 
|  | void resetRequiredChildren() { | 
|  | ArrayList<Element> requiredChildren = this.requiredChilden; | 
|  | if (requiredChildren != null) { | 
|  | for (int i = requiredChildren.size() - 1; i >= 0; i--) { | 
|  | requiredChildren.get(i).visited = false; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Throws an exception if a required child was not present. | 
|  | */ | 
|  | void checkRequiredChildren(Locator locator) throws SAXParseException { | 
|  | ArrayList<Element> requiredChildren = this.requiredChilden; | 
|  | if (requiredChildren != null) { | 
|  | for (int i = requiredChildren.size() - 1; i >= 0; i--) { | 
|  | Element child = requiredChildren.get(i); | 
|  | if (!child.visited) { | 
|  | throw new BadXmlException( | 
|  | "Element named " + this + " is missing required" | 
|  | + " child element named " | 
|  | + child + ".", locator); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } |