001: /*
002: Copyright (C) 2003 Together
003:
004: This library is free software; you can redistribute it and/or
005: modify it under the terms of the GNU Lesser General Public
006: License as published by the Free Software Foundation; either
007: version 2.1 of the License, or (at your option) any later version.
008:
009: This library is distributed in the hope that it will be useful,
010: but WITHOUT ANY WARRANTY; without even the implied warranty of
011: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: Lesser General Public License for more details.
013:
014: You should have received a copy of the GNU Lesser General Public
015: License along with this library; if not, write to the Free Software
016: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package org.enhydra.xml;
020:
021: import java.io.IOException;
022: import java.util.ArrayList;
023: import java.util.List;
024:
025: //import org.apache.xerces.parsers.DOMParser;
026: import org.w3c.dom.DOMException;
027: import org.w3c.dom.Document;
028: import org.w3c.dom.Node;
029: import org.w3c.dom.NodeList;
030: import org.w3c.dom.Element;
031: import org.xml.sax.SAXException;
032:
033: /**
034: * @author Tweety
035: *
036: * A class representing a node in a meta-data tree, which implements
037: * the <a href="../../../../api/org/w3c/dom/Element.html">
038: *
039: * <p> Namespaces are ignored in this implementation. The terms "tag
040: * name" and "node name" are always considered to be synonymous.
041: *
042: * @version 1.0
043: */
044: public class SearchElement extends HashMapElement {
045:
046: public static String TAG_SEPARATOR = "/";
047: public static String ATTR_SEPARATOR = "@";
048: public static String EQUAL_SEPARATOR = "=";
049:
050: /**
051: * Constructs an empty <code>SearchElement</code>.
052: */
053: public SearchElement() {
054: }
055:
056: /**
057: * Constructs an <code>SearchElement</code> with a given document owner and node name.
058: *
059: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
060: * @param name the name of the node, as a <code>String</code>.
061: */
062: public SearchElement(Document ownerDoc, String name) {
063: super (ownerDoc, name);
064: }
065:
066: /**
067: * Constructs an <code>SearchElement</code> with a given <code>Node</code>.
068: *
069: * @param node <code>Node</code>.
070: */
071: public SearchElement(Node node) {
072: super (node);
073: }
074:
075: /**
076: * Constructs an <code>SearchElement</code> with a given <code>SearchElement</code>.
077: *
078: * @param node <code>SearchElement</code>.
079: */
080: public SearchElement(SearchElement node) {
081: super ((HashMapElement) node);
082: }
083:
084: /**
085: * @return new <code>SearchElement</code> instance from a given <code>Node</code>.
086: *
087: * @param node <code>Node</code>.
088: */
089: protected Node newElementInstance(Node node) {
090: return new SearchElement(node);
091: }
092:
093: /**
094: * Creates new instance of <code>SearchElement</code> from a given document
095: * as a <code>Document</code>.
096: *
097: * @param document document.
098: *
099: * @return new <code>SearchElement</code> node as a root of the <code>Document</code>.
100: */
101: public static Element newInstance(Document document) {
102: Node root = document.getDocumentElement();
103: return new SearchElement(root);
104: }
105:
106: /**
107: * Returns a list of elements in the subtree of this node, with the given tag name.
108: *
109: * @param namePath relative path to the </code>Element</code> (through children).
110: *
111: * @return list of elements in the subtree of this node, with the given tag name.
112: */
113: public NodeList getSubElementsByTagName(String namePath) {
114: List list = new ArrayList();
115: getSubElementsByTagName(namePath, list);
116: return new NodeListImpl(list);
117: }
118:
119: /*
120: * Recursively fullfills the <code>list</code> with all the nodes on the given path.
121: */
122: private void getSubElementsByTagName(String name, List list) {
123: // String[] keys = name.split(this.TAG_SEPARATOR, 2);
124: String[] keys = split(name, this .TAG_SEPARATOR);
125: if (keys.length == 1) {
126: List l = (List) this .children.get(name);
127: if (l != null)
128: list.addAll(l);
129: return;
130: }
131: NodeList tagChildren = this .getChildrenByTagName(keys[0]);
132: if (tagChildren != null)
133: for (int i = 0; i < tagChildren.getLength(); i++)
134: ((SearchElement) tagChildren.item(i))
135: .getSubElementsByTagName(keys[1], list);
136: }
137:
138: /**
139: * Returns a list of <code>Element</code>s in the subtree of this node,
140: * which contain attribute with the given name and value.
141: *
142: * @param attrPath relative path to the attribute name.
143: * @param attrValue attribute value.
144: *
145: * @return list of <code>Element</code>s in the subtree of this node,
146: * which contain attribute with the given name and value.
147: */
148: public NodeList getSubElementsByAttrValue(String attrPath,
149: String attrValue) {
150: // String[] keys = attrPath.split(this.ATTR_SEPARATOR, 2);
151: String[] keys = split(attrPath, this .ATTR_SEPARATOR);
152: if (keys.length != 2)
153: throw new DOMException(DOMException.INVALID_ACCESS_ERR,
154: "Parameter not supported");
155: List list = new ArrayList();
156: getSubElementsByAttrValue(keys[0], keys[1], attrValue, list);
157: return new NodeListImpl(list);
158: }
159:
160: /*
161: * Recursively fullfills the <code>list</code> with all the nodes in the given path.
162: */
163: private void getSubElementsByAttrValue(String tagName,
164: String attrName, String attrValue, List list) {
165: // String[] keys = tagName.split(this.TAG_SEPARATOR, 2);
166: String[] keys = split(tagName, this .TAG_SEPARATOR);
167: if (keys.length == 1) {
168: List fList = (List) this .children.get(tagName);
169: if (fList != null) {
170: for (int i = 0; i < fList.size(); i++) {
171: Element elm = (Element) fList.get(i);
172: String val = (String) elm.getAttribute(attrName);
173: if (val != null)
174: if (val.equals(attrValue))
175: list.add(elm);
176: }
177: }
178: return;
179: }
180: NodeList tagChildren = this .getChildrenByTagName(keys[0]);
181: if (tagChildren != null) {
182: for (int i = 0; i < tagChildren.getLength(); i++)
183: ((SearchElement) tagChildren.item(i))
184: .getSubElementsByAttrValue(keys[1], attrName,
185: attrValue, list);
186: }
187: }
188:
189: /**
190: * Returns a list of <code>Element</code>s in the subtree of this node,
191: * with the given tag name and value.
192: *
193: * @param tagPath relative path to the tag name.
194: * @param tagValue <code>Element</code> value.
195: *
196: * @return list of <code>Element</code>s in the subtree of this node,
197: * with the given tag name and value.
198: */
199: public NodeList getSubElementsByTagText(String tagPath,
200: String tagValue) {
201: List list = new ArrayList();
202: getSubElementsByTagText(tagPath, tagValue, list);
203: return new NodeListImpl(list);
204: }
205:
206: /*
207: * Recursively fullfills the <code>list</code> with all the nodes in the given path.
208: * If there is no text node ( text node have value null , -e.g <tag></tag>), this can be matched if
209: * parameter tagValue have value "null".
210: */
211: private void getSubElementsByTagText(String tagName,
212: String tagValue, List list) {
213: // String[] keys = tagName.split(this.TAG_SEPARATOR, 2);
214: String[] keys = split(tagName, this .TAG_SEPARATOR);
215: if (keys.length == 1) {
216: List fList = (List) this .children.get(tagName);
217: if (fList != null) {
218: for (int i = 0; i < fList.size(); i++) {
219: HashMapElement elm = (HashMapElement) fList.get(i);
220: String val = (String) elm.getText();
221: if (val != null) {
222: if (val.equals(tagValue))
223: list.add(elm);
224: } else {
225: if ("null".equals(tagValue))
226: list.add(elm);
227: }
228: }
229: }
230: return;
231: }
232: NodeList tagChildren = this .getChildrenByTagName(keys[0]);
233: if (tagChildren != null) {
234: for (int i = 0; i < tagChildren.getLength(); i++)
235: ((SearchElement) tagChildren.item(i))
236: .getSubElementsByTagText(keys[1], tagValue,
237: list);
238: }
239: }
240:
241: /**
242: * Check that the node is either <code>null</code> or an
243: * <code>NodeImpl</code>.
244: *
245: * @exception DOMException if node is not an instance of <code>NodeImpl</code>.
246: */
247: // protected void checkNode(Node node) throws DOMException {
248: // if (node == null) {
249: // return;
250: // }
251: // if (!(node instanceof SearchElement))
252: // throw new NodeDOMException(DOMException.WRONG_DOCUMENT_ERR, "Node is not an instance of SearchElement!");
253: // }
254: /**
255: * Returns a list of <code>Element</code>s in the subtree of this node,
256: * that satisfy the given condition.
257: *
258: * @param condition condition.
259: *
260: * @return list of <code>Element</code>s in the subtree of this node,
261: * that satisfy the given condition.
262: */
263: public NodeList getSubElementsByCondition(String condition) {
264: //code below does not work with jdk1.3
265: // if (!condition.matches("([^@=]*)(@?[^@=/]*=[^@=/]*)"))
266: // throw new DOMException(
267: // DOMException.INVALID_ACCESS_ERR,
268: // "Parameter not supported");
269: // String[] keys = condition.split(this.EQUAL_SEPARATOR, 2);
270: String[] keys = split(condition, this .EQUAL_SEPARATOR);
271: String namePath = keys[0];
272: if (namePath.indexOf(ATTR_SEPARATOR) != -1)
273: return getSubElementsByAttrValue(namePath, keys[1]);
274: else
275: return getSubElementsByTagText(namePath, keys[1]);
276: }
277:
278: /**
279: * Returns the first <code>Element</code> in the subtree of this node,
280: * that satisfy the given condition.
281: *
282: * @param condition condition.
283: *
284: * @return the first <code>Element</code> in the subtree of this node,
285: * that satisfy the given condition.
286: */
287: public Element getFirstSubElementsByCondition(String condition) {
288: NodeList nodes = getSubElementsByCondition(condition);
289: if (nodes != null && nodes.getLength() > 0)
290: return (Element) nodes.item(0);
291: return null;
292: }
293:
294: /**
295: * Returns the first <code>Element</code> in the subtree of this node,
296: * with the given tag name.
297: *
298: * @param namePath relative path to the <code>Element</code>.
299: *
300: * @return the first <code>Element</code> in the subtree of this node,
301: * with the given tag name.
302: */
303: public Element getFirstSubElementByTagName(String namePath) {
304: NodeList nodes = getSubElementsByTagName(namePath);
305: if (nodes != null && nodes.getLength() > 0)
306: return (Element) nodes.item(0);
307: return null;
308: }
309:
310: /**
311: * Return the text of the <code>Element</code> found on the given path.
312: *
313: * @param namePath relative path to the <code>Element</code> node.
314: *
315: * @return text of the <code>Element</code> found on the given path.
316: */
317: public String getText(String namePath) {
318: NodeList nodes = this .getSubElementsByTagName(namePath);
319: if (nodes != null && nodes.getLength() > 0)
320: return ((SearchElement) nodes.item(0)).getText();
321: return null;
322: }
323:
324: /**
325: * Sets the given text to the <code>Element</code> found on the given path.
326: *
327: * @param namePath relative path to the <code>Element</code> node.
328: * @param text new text.
329: */
330: public void setText(String namePath, String text) {
331: NodeList nodes = this .getSubElementsByTagName(namePath);
332: if (nodes != null && nodes.getLength() > 0)
333: ((SearchElement) nodes.item(0)).setText(text);
334: }
335:
336: /**
337: * Sets the value of an attribute found on the given path.
338: *
339: * @param namePath relative path to the attribute.
340: * @param value is new value.
341: */
342: public void setAttr(String namePath, String value) {
343: //code below does not work with jdk1.3
344: // if (!namePath.matches("([^@]*)(@[^@/]*)"))
345: // throw new DOMException(
346: // DOMException.INVALID_ACCESS_ERR,
347: // "Parameter not supported");
348: // String[] keys = namePath.split(this.ATTR_SEPARATOR, 2);
349: String[] keys = split(namePath, this .ATTR_SEPARATOR);
350:
351: NodeList nodes = this .getSubElementsByTagName(keys[0]);
352: if (nodes != null && nodes.getLength() > 0)
353: ((SearchElement) nodes.item(0))
354: .setAttribute(keys[1], value);
355: }
356:
357: private String[] split(String toSeparate, String separator) {
358: String[] keys = new String[2];
359: int index = toSeparate.indexOf(separator);
360: if (index == -1) {
361: keys = new String[1];
362: keys[0] = toSeparate;
363: } else {
364: keys[0] = toSeparate.substring(0, index);
365: keys[1] = toSeparate.substring(index + 1, toSeparate
366: .length());
367: }
368: return keys;
369: }
370:
371: }
|