001: package org.enhydra.xml;
002:
003: import java.util.ArrayList;
004: import java.util.List;
005:
006: import org.w3c.dom.DOMException;
007: import org.w3c.dom.Document;
008: import org.w3c.dom.Element;
009: import org.w3c.dom.Node;
010: import org.w3c.dom.NodeList;
011:
012: /**
013: * @author Tweety
014: *
015: * A class representing a node in a meta-data tree, which implements
016: * the <a href="../../../../api/org/w3c/dom/Element.html">
017: *
018: * <p> Namespaces are ignored in this implementation. The terms "tag
019: * name" and "node name" are always considered to be synonymous.
020: *
021: * @version 1.0
022: */
023: public class SearchElement extends HashMapElement {
024:
025: public static String TAG_SEPARATOR = "/";
026: public static String ATTR_SEPARATOR = "@";
027: public static String EQUAL_SEPARATOR = "=";
028:
029: /**
030: * Constructs an empty <code>SearchElement</code>.
031: */
032: public SearchElement() {
033: }
034:
035: /**
036: * Constructs an <code>SearchElement</code> with a given document owner and node name.
037: *
038: * @param ownerDoc the document owner of the node, as a <code>Document</code>.
039: * @param name the name of the node, as a <code>String</code>.
040: */
041: public SearchElement(Document ownerDoc, String name) {
042: super (ownerDoc, name);
043: }
044:
045: /**
046: * Constructs an <code>SearchElement</code> with a given <code>Node</code>.
047: *
048: * @param node <code>Node</code>.
049: */
050: public SearchElement(Node node) {
051: super (node);
052: }
053:
054: /**
055: * Constructs an <code>SearchElement</code> with a given <code>SearchElement</code>.
056: *
057: * @param node <code>SearchElement</code>.
058: */
059: public SearchElement(SearchElement node) {
060: super ((HashMapElement) node);
061: }
062:
063: /**
064: * Returns new <code>SearchElement</code> instance from a given <code>Node</code>.
065: *
066: * @param node <code>Node</code>.
067: */
068: protected Node newElementInstance(Node node) {
069: return new SearchElement(node);
070: }
071:
072: /**
073: * Creates new instance of <code>SearchElement</code> from a given document
074: * as a <code>Document</code>.
075: *
076: * @param document document.
077: *
078: * @return new <code>SearchElement</code> node as a root of the <code>Document</code>.
079: */
080: public static Element newInstance(Document document) {
081: Node root = document.getDocumentElement();
082: return new SearchElement(root);
083: }
084:
085: /**
086: * Returns a list of elements in the subtree of this node, with the given tag name.
087: *
088: * @param namePath relative path to the </code>Element</code> (through children).
089: *
090: * @return list of elements in the subtree of this node, with the given tag name.
091: */
092: public NodeList getSubElementsByTagName(String namePath) {
093: List list = new ArrayList();
094: getSubElementsByTagName(namePath, list);
095: return new NodeListImpl(list);
096: }
097:
098: /*
099: * Recursively fullfills the <code>list</code> with all the nodes on the given path.
100: */
101: private void getSubElementsByTagName(String name, List list) {
102: String[] keys = name.split(this .TAG_SEPARATOR, 2);
103: if (keys.length == 1) {
104: List l = (List) this .children.get(name);
105: if (l != null)
106: list.addAll(l);
107: return;
108: }
109: NodeList tagChildren = this .getChildrenByTagName(keys[0]);
110: if (tagChildren != null)
111: for (int i = 0; i < tagChildren.getLength(); i++)
112: ((SearchElement) tagChildren.item(i))
113: .getSubElementsByTagName(keys[1], list);
114: }
115:
116: /**
117: * Returns a list of <code>Element</code>s in the subtree of this node,
118: * which contain attribute with the given name and value.
119: *
120: * @param attrPath relative path to the attribute name.
121: * @param attrValue attribute value.
122: *
123: * @return list of <code>Element</code>s in the subtree of this node,
124: * which contain attribute with the given name and value.
125: */
126: public NodeList getSubElementsByAttrValue(String attrPath,
127: String attrValue) {
128: String[] keys = attrPath.split(this .ATTR_SEPARATOR, 2);
129: if (keys.length != 2)
130: throw new DOMException(DOMException.INVALID_ACCESS_ERR,
131: "Parameter not supported");
132: List list = new ArrayList();
133: getSubElementsByAttrValue(keys[0], keys[1], attrValue, list);
134: return new NodeListImpl(list);
135: }
136:
137: /*
138: * Recursively fullfills the <code>list</code> with all the nodes in the given path.
139: */
140: private void getSubElementsByAttrValue(String tagName,
141: String attrName, String attrValue, List list) {
142: String[] keys = tagName.split(this .TAG_SEPARATOR, 2);
143: if (keys.length == 1) {
144: List fList = (List) this .children.get(tagName);
145: if (fList != null) {
146: for (int i = 0; i < fList.size(); i++) {
147: Element elm = (Element) fList.get(i);
148: String val = (String) elm.getAttribute(attrName);
149: if (val != null)
150: if (val.equals(attrValue))
151: list.add(elm);
152: }
153: }
154: return;
155: }
156: NodeList tagChildren = this .getChildrenByTagName(keys[0]);
157: if (tagChildren != null) {
158: for (int i = 0; i < tagChildren.getLength(); i++)
159: ((SearchElement) tagChildren.item(i))
160: .getSubElementsByAttrValue(keys[1], attrName,
161: attrValue, list);
162: }
163: }
164:
165: /**
166: * Returns a list of <code>Element</code>s in the subtree of this node,
167: * with the given tag name and value.
168: *
169: * @param tagPath relative path to the tag name.
170: * @param tagValue <code>Element</code> value.
171: *
172: * @return list of <code>Element</code>s in the subtree of this node,
173: * with the given tag name and value.
174: */
175: public NodeList getSubElementsByTagText(String tagPath,
176: String tagValue) {
177: List list = new ArrayList();
178: getSubElementsByTagText(tagPath, tagValue, list);
179: return new NodeListImpl(list);
180: }
181:
182: /*
183: * Recursively fullfills the <code>list</code> with all the nodes in the given path.
184: */
185: private void getSubElementsByTagText(String tagName,
186: String tagValue, List list) {
187: String[] keys = tagName.split(this .TAG_SEPARATOR, 2);
188: if (keys.length == 1) {
189: List fList = (List) this .children.get(tagName);
190: if (fList != null) {
191: for (int i = 0; i < fList.size(); i++) {
192: HashMapElement elm = (HashMapElement) fList.get(i);
193: String val = (String) elm.getText();
194: if (val != null)
195: if (val.equals(tagValue))
196: list.add(elm);
197: }
198: }
199: return;
200: }
201: NodeList tagChildren = this .getChildrenByTagName(keys[0]);
202: if (tagChildren != null) {
203: for (int i = 0; i < tagChildren.getLength(); i++)
204: ((SearchElement) tagChildren.item(i))
205: .getSubElementsByTagText(keys[1], tagValue,
206: list);
207: }
208: }
209:
210: /**
211: * Returns a list of <code>Element</code>s in the subtree of this node,
212: * that satisfy the given condition.
213: *
214: * @param condition condition.
215: *
216: * @return list of <code>Element</code>s in the subtree of this node,
217: * that satisfy the given condition.
218: */
219: public NodeList getSubElementsByCondition(String condition) {
220: if (!condition.matches("([^@=]*)(@?[^@=/]*=[^@=/]*)"))
221: throw new DOMException(DOMException.INVALID_ACCESS_ERR,
222: "Parameter not supported");
223: String[] keys = condition.split(this .EQUAL_SEPARATOR, 2);
224: String namePath = keys[0];
225: if (namePath.indexOf(ATTR_SEPARATOR) != -1)
226: return getSubElementsByAttrValue(namePath, keys[1]);
227: else
228: return getSubElementsByTagText(namePath, keys[1]);
229: }
230:
231: /**
232: * Returns the first <code>Element</code> in the subtree of this node,
233: * that satisfy the given condition.
234: *
235: * @param condition condition.
236: *
237: * @return the first <code>Element</code> in the subtree of this node,
238: * that satisfy the given condition.
239: */
240: public Element getFirstSubElementsByCondition(String condition) {
241: NodeList nodes = getSubElementsByCondition(condition);
242: if (nodes != null && nodes.getLength() > 0)
243: return (Element) nodes.item(0);
244: return null;
245: }
246:
247: /**
248: * Returns the first <code>Element</code> in the subtree of this node,
249: * with the given tag name.
250: *
251: * @param namePath relative path to the <code>Element</code>.
252: *
253: * @return the first <code>Element</code> in the subtree of this node,
254: * with the given tag name.
255: */
256: public Element getFirstSubElementByTagName(String namePath) {
257: NodeList nodes = getSubElementsByTagName(namePath);
258: if (nodes != null && nodes.getLength() > 0)
259: return (Element) nodes.item(0);
260: return null;
261: }
262:
263: /**
264: * Return the text of the <code>Element</code> found on the given path.
265: *
266: * @param namePath relative path to the <code>Element</code> node.
267: *
268: * @return text of the <code>Element</code> found on the given path.
269: */
270: public String getText(String namePath) {
271: NodeList nodes = this .getSubElementsByTagName(namePath);
272: if (nodes != null && nodes.getLength() > 0)
273: return ((SearchElement) nodes.item(0)).getText();
274: return null;
275: }
276:
277: /**
278: * Sets the given text to the <code>Element</code> found on the given path.
279: *
280: * @param namePath relative path to the <code>Element</code> node.
281: * @param text new text.
282: */
283: public void setText(String namePath, String text) {
284: NodeList nodes = this .getSubElementsByTagName(namePath);
285: if (nodes != null && nodes.getLength() > 0)
286: ((SearchElement) nodes.item(0)).setText(text);
287: }
288:
289: /**
290: * Sets the value of an attribute found on the given path.
291: *
292: * @param namePath relative path to the attribute.
293: * @param text new value.
294: */
295: public void setAttr(String namePath, String value) {
296: if (!namePath.matches("([^@]*)(@[^@/]*)"))
297: throw new DOMException(DOMException.INVALID_ACCESS_ERR,
298: "Parameter not supported");
299: String[] keys = namePath.split(this .ATTR_SEPARATOR, 2);
300:
301: NodeList nodes = this .getSubElementsByTagName(keys[0]);
302: if (nodes != null && nodes.getLength() > 0)
303: ((SearchElement) nodes.item(0))
304: .setAttribute(keys[1], value);
305: }
306:
307: }
|