205 lines
6.3 KiB
Java
205 lines
6.3 KiB
Java
/*
|
|
* 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<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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|