/* * 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; import android.util.Log; /** * 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 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(); 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 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 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); } } } } }