001: /*
002: * Copyright (c) 2001, Jacob Smullyan.
003: *
004: * This is part of SkunkDAV, a WebDAV client. See http://skunkdav.sourceforge.net/
005: * for the latest version.
006: *
007: * SkunkDAV is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License as published
009: * by the Free Software Foundation; either version 2, or (at your option)
010: * any later version.
011: *
012: * SkunkDAV is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with SkunkDAV; see the file COPYING. If not, write to the Free
019: * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
020: * 02111-1307, USA.
021: */
022:
023: package org.skunk.minixml;
024:
025: import java.util.ArrayList;
026: import java.util.Collections;
027: import java.util.HashMap;
028: import java.util.List;
029: import java.util.ListIterator;
030: import org.skunk.trace.Debug;
031:
032: /**
033: * a minimal tool for constructing Strings that are XML elements.
034: * This is not an all-purpose XML library.
035: */
036: public class XMLElement {
037: private String elementName;
038: private String elementNamespaceCode;
039: private List attributes = Collections
040: .synchronizedList(new ArrayList());
041: private List children = Collections
042: .synchronizedList(new ArrayList());
043: private XMLElement parent = null;
044: private String defaultNamespace = null;
045: private HashMap namespaceHash = new HashMap();
046:
047: public static final String XMLNS_ATTR = "xmlns";
048:
049: public XMLElement(String fullElementName) {
050: int colonIndex = fullElementName.indexOf(":");
051: this .elementName = fullElementName.substring(colonIndex + 1);
052: this .elementNamespaceCode = (colonIndex == -1) ? ""
053: : fullElementName.substring(0, colonIndex);
054: }
055:
056: public XMLElement(String elementName, String namespaceCode,
057: String namespace) {
058: Debug.trace(this , Debug.DP5,
059: "elementName: {0}, namespaceCode: {1}, namespace: {2}",
060: new Object[] { elementName, namespaceCode, namespace });
061:
062: this .elementName = elementName;
063: this .elementNamespaceCode = namespaceCode;
064: if (namespaceCode != null && namespaceCode.length() > 0
065: && namespace != null && namespace.length() > 0) {
066: StringBuffer attrBuffer = new StringBuffer(XMLNS_ATTR);
067: attrBuffer.append(':');
068: attrBuffer.append(namespaceCode);
069: setAttribute(attrBuffer.toString(), namespace);
070: }
071: }
072:
073: public XMLElement(String elementName, String namespaceCode) {
074: this (elementName, namespaceCode, null);
075: }
076:
077: public String getFullElementName() {
078: if (elementNamespaceCode != null
079: && elementNamespaceCode.length() > 0) {
080: StringBuffer sb = new StringBuffer(elementNamespaceCode);
081: sb.append(':');
082: sb.append(elementName);
083: return sb.toString();
084: }
085: return elementName;
086: }
087:
088: public String getElementName() {
089: return elementName;
090: }
091:
092: public String getElementNamespaceCode() {
093: return elementNamespaceCode;
094: }
095:
096: public XMLElement setAttribute(String name, String value) {
097: if (name == null || value == null)
098: throw new IllegalArgumentException(
099: "nulls not supported for xml attributes");
100: if (name.startsWith(XMLNS_ATTR)) {
101: int colonIndex = name.indexOf(":");
102: if (colonIndex == -1) {
103: setDefaultNamespace(value);
104: } else
105: setNamespace(name.substring(colonIndex + 1), value);
106: }
107: for (ListIterator li = attributes.listIterator(); li.hasNext();) {
108: XMLAttribute attr = (XMLAttribute) li.next();
109: if (attr.getName().equals(name)) {
110: attr.setValue(value);
111: return this ;
112: }
113: }
114: attributes.add(new XMLAttribute(name, value));
115: return this ;
116: }
117:
118: public String getAttribute(String name) {
119: for (ListIterator li = attributes.listIterator(); li.hasNext();) {
120: XMLAttribute attr = (XMLAttribute) li.next();
121: if (attr.getName().equals(name))
122: return attr.getValue();
123: }
124: return null;
125: }
126:
127: public ListIterator attributes() {
128: return attributes.listIterator();
129: }
130:
131: public ListIterator children() {
132: return children.listIterator();
133: }
134:
135: public XMLElement addChild(Object child) {
136: children.add(child);
137: if (child instanceof XMLElement)
138: ((XMLElement) child).setParent(this );
139: return this ;
140: }
141:
142: /**
143: * this method ignores namespace
144: */
145: public XMLElement getChild(String elementName, int index) {
146: int i = 0;
147: for (ListIterator lit = children.listIterator(); lit.hasNext();) {
148: Object child = lit.next();
149: if (child instanceof XMLElement
150: && ((XMLElement) child).getElementName().equals(
151: elementName)) {
152: if (i == index)
153: return (XMLElement) child;
154: else
155: i++;
156: }
157: }
158: return null;
159: }
160:
161: public XMLElement getChildElement(int index) {
162: if (index >= children.size())
163: return null;
164: int i = 0;
165: for (ListIterator lit = children.listIterator(); lit.hasNext();) {
166: Object o = lit.next();
167: if (o instanceof XMLElement) {
168: if (index == (i++)) {
169: return (XMLElement) o;
170: }
171: }
172: }
173: return null;
174: }
175:
176: public Object getChild(int index) {
177: if (index < children.size())
178: return children.get(index);
179: return null;
180: }
181:
182: /**
183: * this method ignores namespace and returns the first matching child
184: */
185: public XMLElement getChild(String elementName) {
186: return getChild(elementName, 0);
187: }
188:
189: /**
190: * returns the first matching child
191: */
192: public XMLElement getChild(String elementName, String namespace) {
193: return getChild(elementName, namespace, 0);
194: }
195:
196: public XMLElement getChild(String elementName, String namespace,
197: int index) {
198: int i = 0;
199: for (ListIterator lit = children.listIterator(); lit.hasNext();) {
200: Object child = lit.next();
201: if (child instanceof XMLElement) {
202: Debug.trace(this , Debug.DP5, "child element: {0}",
203: child);
204: XMLElement childElem = (XMLElement) child;
205: if (childElem.getElementName().equals(elementName)) {
206: String childNamespace = childElem
207: .getNamespace(childElem
208: .getElementNamespaceCode());
209: Debug.trace(this , Debug.DP5,
210: "child namespace: {0}", childNamespace);
211: if (namespace == null) {
212: if (childNamespace == null) {
213: if (i == index)
214: return childElem;
215: else
216: i++;
217: }
218: } else if (childNamespace != null
219: && childNamespace.equals(namespace)) {
220: if (i == index)
221: return childElem;
222: else
223: i++;
224: }
225: }
226: }
227: }
228: return null;
229: }
230:
231: public boolean isEmpty() {
232: return children.isEmpty();
233: }
234:
235: public String toString() {
236: StringBuffer sb = new StringBuffer();
237: sb.append('<');
238: if (elementNamespaceCode.length() > 0) {
239: sb.append(elementNamespaceCode);
240: sb.append(':');
241: }
242: sb.append(elementName);
243: for (ListIterator li = attributes.listIterator(); li.hasNext();) {
244: XMLAttribute attr = (XMLAttribute) li.next();
245: sb.append(' ');
246: sb.append(attr.getName());
247: sb.append("=\"");
248: sb.append(attr.getValue());
249: sb.append("\"");
250: }
251: if (!isEmpty()) {
252: sb.append('>');
253: for (ListIterator li = children.listIterator(); li
254: .hasNext();) {
255: sb.append(li.next());
256: }
257: sb.append("</");
258: if (elementNamespaceCode.length() > 0) {
259: sb.append(elementNamespaceCode);
260: sb.append(':');
261: }
262: sb.append(elementName);
263: sb.append('>');
264: } else {
265: sb.append("/>");
266: }
267: return sb.toString();
268: }
269:
270: private void setDefaultNamespace(String id) {
271: this .defaultNamespace = id;
272: }
273:
274: private void setNamespace(String name, String id) {
275: Debug.trace(this , Debug.DP5,
276: "in setNamespace with element {0}, name {1}, id {2}",
277: new Object[] { this , name, id });
278: this .namespaceHash.put(name, id);
279: this .elementNamespaceCode = name;
280: }
281:
282: public String getDefaultNamespace() {
283: //elements leave the default namespace null unless
284: //they or their parent have a defined default namespace
285: if (this .defaultNamespace == null) {
286: if (this .parent != null) {
287: return parent.getDefaultNamespace();
288: } else
289: return "";
290: } else
291: return this .defaultNamespace;
292: }
293:
294: public String getNamespace(String namespaceCode) {
295: if (namespaceHash.containsKey(namespaceCode))
296: return namespaceHash.get(namespaceCode).toString();
297: else if (parent != null)
298: return parent.getNamespace(namespaceCode);
299: return null;
300: }
301:
302: public String getNamespace() {
303: return getNamespace(getElementNamespaceCode());
304: }
305:
306: protected void setParent(XMLElement parent) {
307: this .parent = parent;
308: }
309: }
310:
311: /* $Log: XMLElement.java,v $
312: /* Revision 1.11 2001/09/01 18:25:56 smulloni
313: /* fixes for Zope interoperability; version 1.0.2.4 dev
314: /*
315: /* Revision 1.10 2001/07/17 03:00:04 smulloni
316: /* added XMLCData class to represent CDATA, and fixed CDATA parsing, which was
317: /* wrong in any case; added license preambles where I had forgotten to put them.
318: /*
319: /* Revision 1.9 2000/11/09 23:35:11 smullyan
320: /* log added to every Java file, with the help of python. Lock stealing
321: /* implemented, and treatment of locks made more robust.
322: /* */
|