1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.wangs.xmlutil;
21
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.text.DateFormat;
27 import java.util.Hashtable;
28 import java.util.Vector;
29
30 import javax.xml.parsers.DocumentBuilder;
31 import javax.xml.parsers.DocumentBuilderFactory;
32 import javax.xml.parsers.ParserConfigurationException;
33
34 import org.w3c.dom.Document;
35 import org.w3c.dom.Element;
36 import org.w3c.dom.NamedNodeMap;
37 import org.w3c.dom.Node;
38 import org.w3c.dom.NodeList;
39 import org.xml.sax.SAXException;
40
41 /***
42 * <pre>
43 * XMLUtil constructs from either an xml file or a node, and returns detail information of
44 * node by directory style path into easy-to-use data formats, such as String, int, Hashtable
45 * of String, etc.
46 *
47 * Demonstration of the usage of XMLUtil:
48 *
49 * try {
50 * String path = "/AAA/BBB/CCC";
51 *
52 * // You can directly construct an XMLUtil object from XPath like below:
53 * // XMLUtil util = new XMLUtil("./config/sample.xml");
54 * // Vector nodes = util.getNodes(path);
55 *
56 * // Or you can construct an XMLUtil object from a node (normally also from XMLUtil)
57 * Vector nodes = XMLUtil.getNodes(path);
58 * for(int i=0; i<nodes.size(); i++) {
59 * Node node = (Node)nodes.elementAt(i);
60 * XMLUtil xMLUtil = new XMLUtil(node);
61 * String val = xMLUtil.getNodeValue("/BBB/CCC", 1);
62 * Hashtable hash = xMLUtil.getChildNodeHashValues("/CCC");
63 * }
64 * } catch (Exception e) {
65 * e.printStackTrace();
66 * }
67 * </pre>
68 * @author <a href="mailto:yuqingwang_99@yahoo.com">Yuqing Wang</a>
69 */
70
71 public class XMLUtil {
72
73 /***
74 * Return all nodes for given node name with path.
75 * @param nodeName
76 * @return Vector of Node
77 * @throws XMLUtilException
78 * @since 1.0
79 */
80 public Vector getNodes(String nodeName) throws XMLUtilException {
81 return _getNodesByString(_configElem, nodeName);
82 }
83
84 /***
85 * Return all node values for given node name with path.
86 * @return Vector of String
87 * @since 1.0
88 */
89 public Vector getNodeValues(String nodeName) throws XMLUtilException {
90 Vector vNodes = _getNodesByString(_configElem, nodeName);
91
92 if(vNodes == null) {
93 String msg = "***Error: Unknown error. node name may not be supplied";
94 throw new XMLUtilException(msg);
95 }
96
97 if(vNodes.size() == 0) {
98 String msg = "***Error: No such node " + nodeName;
99 throw new XMLUtilException(msg);
100 }
101
102 Vector vString = new Vector();
103
104 for (int i=0; i<vNodes.size(); i++) {
105 Node node = (Node)vNodes.elementAt(i);
106 if(node.hasChildNodes() && node.getNodeType() == Node.ELEMENT_NODE) {
107 Node aNode = node.getFirstChild();
108 if(aNode != null && aNode.getNodeType() == Node.TEXT_NODE) {
109 vString.add(aNode.getNodeValue().trim());
110 }
111 }
112 }
113 return vString;
114 }
115
116 /***
117 * Return all node values in a Hashtable for given node name with path.
118 * The values are converted in their origin type.
119 * @return Hashtable of String for keys and Object for values
120 * @since 1.1
121 */
122 public Hashtable getNodeValuesAsHashtable(String nodeName) throws XMLUtilException {
123 Vector vNodes = _getNodesByString(_configElem, nodeName);
124
125 if(vNodes == null) {
126 String msg = "***Error: Unknown error. node name may not be supplied";
127 throw new XMLUtilException(msg);
128 }
129
130 if(vNodes.size() == 0) {
131 String msg = "***Error: No such node " + nodeName;
132 throw new XMLUtilException(msg);
133 }
134
135 Hashtable vString = new Hashtable();
136
137 for (int i=0; i<vNodes.size(); i++) {
138 Node node = (Node)vNodes.elementAt(i);
139 XMLUtil util = new XMLUtil((Element)node);
140 String key = util.getNamedAttrValue("item", "name", 1);
141 String value = util.getNodeValue("item/value", 1);
142 String type = util.getNamedAttrValue("item", "type", 1);
143
144 if (type == null)
145 type = "String";
146 Object convertedValue = convertType(value, type);
147 vString.put(key, convertedValue);
148 }
149 return vString;
150 }
151
152 /***
153 * Construct a new object in a given type based on a given object value.
154 *
155 * For primative type, please use keywords "int", "short", "long", "double", "char", "byte",
156 * and "boolean", and the value in return Hashtable is the corresponding Object type:
157 * "Integer", "Short", "Long", "Double", "Character", "Byte", and "Boolean".
158 *
159 * For "java.lang.String" the short forms "string" and "String" are also valid.
160 * For "java.util.Date" the short forms "date" and "Date" are also valid. The format of
161 * a valid date field depends on the current locale.
162 *
163 * For the other data type, please specify the full Java type name, such as "java.lang.XXX".
164 *
165 */
166 private Object convertType(String val, String type) throws XMLUtilException{
167 Object newVal = null;
168 DateFormat lDateFormat = DateFormat.getDateInstance();
169
170
171 try {
172 if (type.equals("int"))
173 newVal = new Integer(val);
174 else if (type.equals("short"))
175 newVal = new Short(val);
176 else if (type.equals("long"))
177 newVal = new Long(val);
178 else if (type.equals("char"))
179 newVal = new Character(val.charAt(0));
180 else if (type.equals("byte"))
181 newVal = new Byte(val);
182 else if (type.equals("double"))
183 newVal = new Double(val);
184 else if (type.equals("boolean"))
185 newVal = new Boolean(val);
186 else if (type.equals("java.lang.String") || type.equals("string") || type.equals("String"))
187 newVal = val;
188 else if (type.equals("java.util.Date") || type.equals("date") || type.equals("Date")) {
189 newVal = lDateFormat.parse(val);
190 }
191 else {
192 Class objClass = Class.forName(type);
193 newVal = objClass.getConstructor(new Class[] {(type).getClass()}).newInstance(new Object[] {val});
194 }
195 } catch (Exception e) {
196 throw new XMLUtilException("***Error: error constructing params: type=" + type + " value=" + val + "\nError message: " + e.getMessage());
197 }
198 return newVal;
199 }
200
201
202 /***
203 * Return node for given node name and index
204 * @param nodename - name of the node with full path
205 * @param index - the index number of node that satisfies the nodeName, started from 1, top-down
206 * @since 1.0
207 */
208 public Node getNode(String nodeName, int index) throws XMLUtilException {
209 Vector nodes = getNodes(nodeName);
210 if (nodes.size() < index) {
211 String msg = "***Error: Node's index out of bound: " + nodeName;
212 throw new XMLUtilException(msg);
213 }
214
215 return (Node)nodes.elementAt(index-1);
216 }
217
218
219 /***
220 * Return Vector of nodes for given node name and one given attribute values
221 * More complicated case is to give a hashtable of attribute name-value pairs, but
222 * we are not going to provide this since it's rarely used.
223 * @param nodeName - name of the node with full path
224 * @param attrName - name of attribute in the node
225 * @param attrValue - value of the given attribute
226 * @since 1.0
227 */
228 public Vector getNodesByAttrValue(String nodeName, String attrName, String attrValue) throws XMLUtilException {
229 Vector result = new Vector();
230 Vector nodes = getNodes(nodeName);
231
232 Element elemNode = null;
233 for (int i=0; i<nodes.size(); i++) {
234 elemNode = (Element)nodes.elementAt(i);
235 if (!elemNode.hasAttribute(attrName)) {
236
237 }
238
239 if (elemNode.getAttribute(attrName).equals(attrValue))
240 result.add(elemNode);
241 }
242
243 if (result == null) {
244 String msg = "***Error: Wrong values for node=" + nodeName + ", attribute name=" + attrName + ", attribute value=" + attrValue;
245 throw new XMLUtilException(msg);
246 }
247
248 return result;
249 }
250
251
252 /***
253 * Return node for given node name and one given attribute values
254 * <pre>
255 * If there are multiple nodes satisfied this condition, the first one is returned.
256 * A common usage of this method is: to obtain a particular node from a set of sibling nodes.
257 * All nodes have the same tag name and attribute names. The only way to differentiate one
258 * from them is the attribute value. For example,
259 * <service name="ServiceAAA">
260 * // data belongs to ServiceAAA
261 * </service>
262 * <service name="ServiceBBB">
263 * // data belongs to ServiceBBB
264 * </service>
265 * <service name="ServiceCCC">
266 * // data belongs to ServiceCCC
267 * </service>
268 * More complicated case is to give a hashtable of attribute name-value pairs, but
269 * we are not going to provide this since it's rarely used.
270 * </pre>
271 * @param nodeName - name of the node with full path
272 * @param attrName - name of attribute in the node
273 * @param attrValue - value of the given attribute
274 * @since 1.0
275 */
276 public Node getNodeByAttrValue(String nodeName, String attrName, String attrValue) throws XMLUtilException {
277 Vector nodes = getNodes(nodeName);
278
279 Element elemNode = null;
280 for (int i=0; i<nodes.size(); i++) {
281 elemNode = (Element)nodes.elementAt(i);
282 if (!elemNode.hasAttribute(attrName)) {
283
284 }
285
286 if (elemNode.getAttribute(attrName).equals(attrValue))
287 return elemNode;
288 }
289
290
291 String msg = "SFWK:: Wrong values for node=" + nodeName + ", attribute name=" + attrName + ", attribute value=" + attrValue;
292 throw new XMLUtilException(msg);
293
294 }
295
296
297 /***
298 * Return Vector of nodes for given node name and one given attribute values
299 * <pre>
300 * A common usage of this method is: to obtain a subset of nodes from a set of sibling nodes.
301 * All nodes have the same tag name and attribute names. The only way to differentiate desired
302 * ones from them is the attribute value. For example,
303 * <service name="ServiceAAA">
304 * // data belongs to ServiceAAA
305 * </service>
306 * <service name="ServiceBBB">
307 * // data belongs to ServiceBBB
308 * </service>
309 * <service name="ServiceCCC">
310 * // data belongs to ServiceCCC
311 * </service>
312 * More complicated case is to give a hashtable of attribute name-value pairs, but
313 * we are not going to provide this since it's rarely used.
314 * </pre>
315 * @param nodeName - name of the node with full path
316 * @param attrName - name of attribute in the node
317 * @param attrValue - value of the given attribute
318 * @since 1.0
319 */
320 public String getNodeValueByAttrValue(String nodeName, String attrName, String attrValue)
321 throws XMLUtilException {
322 Node node = getNodeByAttrValue(nodeName, attrName, attrValue);
323
324 if(node.hasChildNodes() && node.getNodeType() == Node.ELEMENT_NODE) {
325 Node aNode = node.getFirstChild();
326 if(aNode != null && aNode.getNodeType() == Node.TEXT_NODE) {
327 return aNode.getNodeValue().trim();
328 }
329 }
330
331
332 return null;
333 }
334
335
336 /***
337 * For a known node, get its value.
338 * If more than one nodes with the same name under
339 * given path, the one in the index (start from "1" Top-Down) is retrieved.
340 * @param nodename - name of the node with full path
341 * @param index - the index number of node that satisfies the nodeName
342 * @return String - string value of node
343 * @exception XMLUtilException
344 * @since 1.0
345 */
346 public String getNodeValue(String nodeName, int index) throws XMLUtilException {
347 Vector vNodes = _getNodesByString(_configElem, nodeName);
348
349 if(vNodes == null) {
350 String msg = "***Error: Unknown error. node name may not be supplied";
351 throw new XMLUtilException(msg);
352 }
353
354 if(vNodes.size() == 0) {
355 String msg = "***Error: No such node " + nodeName;
356 throw new XMLUtilException(msg);
357 }
358
359 Node node = (Node)vNodes.elementAt(index - 1);
360 if(node.hasChildNodes() && node.getNodeType() == Node.ELEMENT_NODE) {
361 Node aNode = node.getFirstChild();
362 if(aNode != null && aNode.getNodeType() == Node.TEXT_NODE) {
363 return aNode.getNodeValue().trim();
364 }
365 }
366
367 return null;
368 }
369
370
371 /***
372 * Given a node name (with path), returns number of nodes with the same
373 * name under the same path.
374 * @param nodename - name of the node with full path
375 * @return int
376 * @exception XMLUtilException
377 * @since 1.0
378 */
379 public int getNodeCount(String nodeName) throws XMLUtilException {
380 Vector vNodes = _getNodesByString(_configElem, nodeName);
381
382 if(vNodes == null) {
383 String msg = "***Error: Unknown error. node name may not be supplied";
384 throw new XMLUtilException(msg);
385 }
386
387 return vNodes.size();
388 }
389
390
391 /***
392 * Given a node name (with path), returns all attributes of this node
393 * with name-value pairs. If more than one nodes with the same name under
394 * given path, the one in the index (start from "1" Top-Down) is retrieved.
395 *
396 * @param nodename - name of the node with full path
397 * @param index - the index number of node that satisfies the nodeName
398 * @return String - string value of node
399 * @exception XMLUtilException
400 * @since 1.0
401 */
402 public Hashtable getAttrValues(String nodeName, int index) throws XMLUtilException {
403
404 Vector vNodes = _getNodesByString(_configElem, nodeName);
405
406 if(vNodes == null) {
407 String msg = "***Error: Unknown error. node name may not be supplied";
408 throw new XMLUtilException(msg);
409 }
410
411 if(vNodes.size() == 0) {
412 String msg = "***Error: No such node " + nodeName;
413 throw new XMLUtilException(msg);
414 }
415
416 Node node = (Node)vNodes.elementAt(index - 1);
417 if (node == null) {
418 String msg = "***Error: Index is wrong";
419 throw new XMLUtilException(msg);
420
421 }
422
423 NamedNodeMap attrMap = node.getAttributes();
424 if (attrMap == null) {
425 return null;
426 }
427
428 Hashtable attrs = new Hashtable();
429 for (int i=0; i<attrMap.getLength(); i++) {
430 Node attrItem = attrMap.item(i);
431 attrs.put(attrItem.getNodeName(), attrItem.getNodeValue());
432 }
433
434 return attrs;
435 }
436
437 /***
438 * Given a node name (with path) and atrribute name, returns attribute value.
439 * If more than one nodes with the same name under given path, the one in the
440 * index (start from "1" Top-Down) is retrieved.
441 *
442 * @param nodename - name of the node with full path
443 * @param attrName - name of the attribute in this node
444 * @param index - the index number of node that satisfies the nodeName
445 * @return String - string value of node
446 * @exception XMLUtilException
447 * @since 1.0
448 */
449 public String getNamedAttrValue(String nodeName, String attrName, int index)
450 throws XMLUtilException {
451 Vector vNodes = _getNodesByString(_configElem, nodeName);
452
453 if(vNodes == null) {
454 String msg = "***Error: Unknown error. node name may not be supplied";
455 throw new XMLUtilException(msg);
456 }
457
458 if(vNodes.size() == 0) {
459 String msg = "***Error: No such node " + nodeName;
460 throw new XMLUtilException(msg);
461 }
462
463 Node node = (Node)vNodes.elementAt(index - 1);
464 if (node == null) {
465 String msg = "***Error: Index is wrong";
466 throw new XMLUtilException(msg);
467
468 }
469
470 NamedNodeMap attrMap = node.getAttributes();
471 if (attrMap == null) {
472 String msg = "***Error: No attributes for the element " + nodeName;
473 throw new XMLUtilException(msg);
474
475 }
476
477 Node attrNode = attrMap.getNamedItem(attrName);
478
479 if (attrNode == null) {
480 String msg = "***Error: No such attribute: " + attrName;
481 throw new XMLUtilException(msg);
482
483 }
484
485 return attrNode.getNodeValue();
486
487 }
488
489
490 /***
491 * Given a node name (with path) and attributes array, returns MultiKeyHashtable of all nodes with
492 * the same name in the same path. The Hash Key is String array of all attributes values.
493 * For example, a node
494 * <pre>
495 * "/AAA/BBB/CCC"
496 * is defined as:
497 * ...
498 * <CCC>
499 * <DDD attrA="a1" attrB="b1">
500 * <EEE>Value1 of EEE</EEE>
501 * <FFF/>
502 * </DDD>
503 * <DDD attrA="a1" attrB="b2">
504 * <EEE>Value2 of EEE</EEE>
505 * <FFF/>
506 * </DDD>
507 * <DDD attrA="a2" attrB="b1">
508 * <EEE>Value3 of EEE</EEE>
509 * <FFF/>
510 * </DDD>
511 * </CCC>
512 * ...
513 * Then
514 * getNodeValuesHashedByNamedAttrs("/AAA/BBB/CCC", new String[] {"attrA", "attrB"})
515 * returns:
516 * Keys Values
517 * -------------------------- -------------------------
518 * {"a1", "b1"} first node of DDD
519 * {"a1", "b2"} second node of DDD
520 * {"a2", "b1"} third node of DDD
521 *
522 * </pre>
523 * @since 1.0
524 */
525
526 public MultiKeyHashtable getNodesHashedByNamedAttrs(String nodeName, String[] attrNames)
527 throws XMLUtilException {
528 Vector vNodes = _getNodesByString(_configElem, nodeName);
529
530 if(vNodes == null) {
531 String msg = "***Error: Unknown error. node name may not be supplied";
532 throw new XMLUtilException(msg);
533 }
534
535 if(vNodes.size() == 0) {
536 String msg = "***Error: No such node " + nodeName;
537 throw new XMLUtilException(msg);
538 }
539
540 MultiKeyHashtable result = new MultiKeyHashtable();
541
542 for (int i=0; i<vNodes.size(); i++) {
543 Node node = (Node)vNodes.elementAt(i);
544 NamedNodeMap attrMap = node.getAttributes();
545 if (attrMap.getLength() == 0 || attrMap == null) {
546
547 } else {
548 String[] keys = new String[attrNames.length];
549 for (int j=0; j<attrNames.length; j++) {
550 Node attrNode = attrMap.getNamedItem(attrNames[j]);
551 if (attrNode != null)
552 keys[j] = attrNode.getNodeValue().trim();
553 else
554 keys[j] = "";
555 }
556 result.put(keys, node);
557 }
558 }
559
560 return result;
561 }
562
563
564 /***
565 * Given a node name (with path) and attributes array, returns all node values with the same name
566 * in the same path. The Hash Key is String array of all attributes values.
567 * For example, a node <p>
568 * "/AAA/BBB/CCC"<p>
569 * is defined as:<p>
570 * <pre>
571 * ...
572 * <CCC>
573 * <DDD attrA="a1" attrB="b1">v1</DDD>
574 * <DDD attrA="a2" attrB="b2">v2</DDD>
575 * <DDD attrA="a3" attrB="b3">v3</DDD>
576 * <DDD attrA="a4" attrB="b4">v4</DDD>
577 * <DDD attrA="a5" attrB="b5">v5</DDD>
578 * </CCC>
579 * ...
580 * </pre>
581 * Then <p>
582 * getNodeValuesHashedByNamedAttrs("/AAA/BBB/CCC",
583 * new String[] {"attrA", "attrB"})<p>
584 * returns:<p>
585 * <pre>
586 * Keys Values
587 * -------------------------- -------------------------
588 * {"a1", "b1"} v1
589 * {"a2", "b2"} v2
590 * {"a3", "b3"} v3
591 * {"a4", "b4"} v4
592 * {"a5", "b5"} v5
593 * </pre>
594 *
595 * This method is a sub case of getNodesHashedByNamedAttrs(), in case the node is leaf.
596 * @since 1.0
597 */
598
599 public MultiKeyHashtable getNodeValuesHashedByNamedAttrs(String nodeName, String[] attrNames)
600 throws XMLUtilException {
601 Vector vNodes = _getNodesByString(_configElem, nodeName);
602
603 if(vNodes == null) {
604 String msg = "***Error: Unknown error. node name may not be supplied";
605 throw new XMLUtilException(msg);
606 }
607
608 if(vNodes.size() == 0) {
609 String msg = "***Error: No such node " + nodeName;
610 throw new XMLUtilException(msg);
611 }
612
613 MultiKeyHashtable result = new MultiKeyHashtable();
614
615 for (int i=0; i<vNodes.size(); i++) {
616 Node node = (Node)vNodes.elementAt(i);
617 NamedNodeMap attrMap = node.getAttributes();
618 if (attrMap.getLength() == 0 || attrMap == null) {
619
620 } else {
621 String[] keys = new String[attrNames.length];
622 for (int j=0; j<attrNames.length; j++) {
623 Node attrNode = attrMap.getNamedItem(attrNames[j]);
624 if (attrNode != null)
625 keys[j] = attrNode.getNodeValue().trim();
626 else
627 keys[j] = "";
628 }
629 String value = "";
630 if(node.hasChildNodes() && node.getNodeType() == Node.ELEMENT_NODE) {
631 Node aNode = node.getFirstChild();
632 if(aNode != null && aNode.getNodeType() == Node.TEXT_NODE) {
633 value = aNode.getNodeValue().trim();
634 }
635 result.put(keys, value);
636 }
637 }
638 }
639
640 return result;
641 }
642
643
644 /***
645 * Given a node name (with path) and one attribute, returns Hashtable of all nodes with
646 * the same name in the same path. The Hash Key is String value of given attribute value.
647 *
648 * This method is a simplified version of getNodeValuesHashedByNamedAttrs(). It takes
649 * only one attribute, and returns Hashtable, instead of MultiKeyHashtable.
650 *
651 * For example, a node
652 * <pre>
653 * "/AAA/some-tag"
654 * is defined as:
655 * ...
656 * <some-tag>
657 * <some-node attrA="a1">
658 * <sub-node>value1</sub-node>
659 * </some-node>
660 * <some-node attrA="a2">
661 * <sub-node>value2</sub-node>
662 * </some-node>
663 * <some-node attrA="a3">
664 * <sub-node>value3</sub-node>
665 * </some-node>
666 * </some-tag>
667 * ...
668 * Then
669 * getNodeValuesHashedByNamedAttr("/AAA/some-tag", "attrA")
670 * returns:
671 * Keys Values
672 * -------------------------- -------------------------
673 * a1 first node of some-node
674 * a2 second node of some-node
675 * a3 third node of some-node
676 *
677 * </pre>
678 * @since 1.0
679 */
680 public Hashtable getNodesHashedByNamedAttr(String nodeName, String attrName)
681 throws XMLUtilException {
682 Vector vNodes = _getNodesByString(_configElem, nodeName);
683
684 if(vNodes == null) {
685 String msg = "***Error: Unknown error. node name may not be supplied";
686 throw new XMLUtilException(msg);
687 }
688
689 if(vNodes.size() == 0) {
690 String msg = "***Error: No such node " + nodeName;
691 throw new XMLUtilException(msg);
692 }
693
694 Hashtable result = new Hashtable();
695
696 for (int i=0; i<vNodes.size(); i++) {
697 Node node = (Node)vNodes.elementAt(i);
698 NamedNodeMap attrMap = node.getAttributes();
699 if (attrMap.getLength() == 0 || attrMap == null) {
700
701 } else {
702 String key = "";
703 Node attrNode = attrMap.getNamedItem(attrName);
704 if (attrNode != null) {
705 key = attrNode.getNodeValue().trim();
706 }
707 result.put(key, node);
708 }
709 }
710
711 return result;
712 }
713
714
715 /***
716 * Given a node name (with path) and one attribute, returns Hashtable of all nodes with
717 * the same name in the same path. The Hash Key is String value of given attribute value.
718 *
719 * This method is a simplified version of getNodeValuesHashedByNamedAttrs(). It takes
720 * only one attribute, and returns Hashtable, instead of MultiKeyHashtable.
721 *
722 * For example, a node
723 * <pre>
724 * "/AAA/some-tag"
725 * is defined as:
726 * ...
727 * <some-tag>
728 * <some-node attrA="a1">
729 * <sub-node>value1</sub-node>
730 * </some-node>
731 * <some-node attrA="a2">
732 * <sub-node>value2</sub-node>
733 * </some-node>
734 * <some-node attrA="a3">
735 * <sub-node>value3</sub-node>
736 * </some-node>
737 * </some-tag>
738 * ...
739 * Then
740 * getNodeValuesHashedByNamedAttr("/AAA/some-tag", "attrA")
741 * returns:
742 * Keys Values
743 * -------------------------- -------------------------
744 * a1 value1
745 * a2 value2
746 * a3 value3
747 *
748 * </pre>
749 * @since 1.0
750 */
751 public Hashtable getNodeValuesHashedByNamedAttr(String nodeName, String attrName)
752 throws XMLUtilException {
753 Vector vNodes = _getNodesByString(_configElem, nodeName);
754
755 if(vNodes == null) {
756 String msg = "***Error: Unknown error. node name may not be supplied";
757 throw new XMLUtilException(msg);
758 }
759
760 if(vNodes.size() == 0) {
761 String msg = "***Error: No such node " + nodeName;
762 throw new XMLUtilException(msg);
763 }
764
765 Hashtable result = new Hashtable();
766
767 for (int i=0; i<vNodes.size(); i++) {
768 Node node = (Node)vNodes.elementAt(i);
769 NamedNodeMap attrMap = node.getAttributes();
770 if (attrMap.getLength() == 0 || attrMap == null) {
771
772 } else {
773 String key = "";
774 Node attrNode = attrMap.getNamedItem(attrName);
775 if (attrNode != null) {
776 key = attrNode.getNodeValue().trim();
777 }
778 String value = "";
779 if(node.hasChildNodes() && node.getNodeType() == Node.ELEMENT_NODE) {
780 Node aNode = node.getFirstChild();
781 if(aNode != null && aNode.getNodeType() == Node.TEXT_NODE) {
782 value = aNode.getNodeValue().trim();
783 }
784 result.put(key, value);
785 }
786 }
787 }
788
789 return result;
790 }
791
792
793 /***
794 * Given node name (with path) and two attribute's names, returns a Hashtable with key is one attribute's value
795 * and value is another attribute's value.
796 *
797 * @param nodeName: the name of node with path
798 * @param val_attrName: name of attribute which value is treated as hash value
799 * @param key_attrName: name of attribute which value is treated as hash key
800 * @return Hashtable
801 * @since 1.0
802 */
803 public Hashtable getAttrValuesHashedByNamedAttr(String nodeName, String val_attrName, String key_attrName)
804 throws XMLUtilException {
805 Vector vNodes = _getNodesByString(_configElem, nodeName);
806
807 if(vNodes == null) {
808 String msg = "SFWK:: Unknown error. node name may not be supplied";
809 throw new XMLUtilException(msg);
810 }
811
812 if(vNodes.size() == 0) {
813 String msg = "SFWK:: No such node " + nodeName;
814 throw new XMLUtilException(msg);
815 }
816
817 Hashtable result = new Hashtable();
818
819 for (int i=0; i<vNodes.size(); i++) {
820 Node node = (Node)vNodes.elementAt(i);
821 NamedNodeMap attrMap = node.getAttributes();
822 if (attrMap.getLength() == 0 || attrMap == null) {
823
824 } else {
825 String key = "";
826 Node key_attrNode = attrMap.getNamedItem(key_attrName);
827 if (key_attrNode != null) {
828 key = key_attrNode.getNodeValue().trim();
829 }
830 if (!key.equals("")) {
831 String value = "";
832 Node val_attrNode = attrMap.getNamedItem(val_attrName);
833 if (val_attrNode != null) {
834 value = val_attrNode.getNodeValue().trim();
835 }
836 result.put(key, value);
837 }
838 }
839 }
840
841 return result;
842 }
843
844
845 /***
846 * Given node name (with path), an attribute name and an array of attribute names, returns a MultiKeyHashtable
847 * with keys from two or more attributes and value from another attribute.
848 *
849 * @param nodeName: the name of node with path
850 * @param val_attrName: name of attribute which value is treated as hash value
851 * @param key_attrName: array of names of attributes which values are treated as hash keys
852 * @return MultiKeyHashtable with results
853 * @since 1.0.3
854 */
855 public MultiKeyHashtable getAttrValuesHashedByNamedAttrs(String nodeName,
856 String val_attrName, String[] key_attrName) throws XMLUtilException {
857
858 Vector vNodes = _getNodesByString(_configElem, nodeName);
859
860 if (vNodes == null) {
861 String msg = "SFWK:: Unknown error. node name may not be supplied";
862 throw new XMLUtilException(msg);
863 }
864
865 if (vNodes.size() == 0) {
866 String msg = "SFWK:: No such node " + nodeName;
867 throw new XMLUtilException(msg);
868 }
869
870 MultiKeyHashtable result = new MultiKeyHashtable();
871
872 for (int i = 0; i < vNodes.size(); i++) {
873 Node node = (Node) vNodes.elementAt(i);
874 NamedNodeMap attrMap = node.getAttributes();
875 if (attrMap.getLength() == 0 || attrMap == null) {
876
877 } else {
878 String[] keys = new String[key_attrName.length];
879 for (int j = 0; j < key_attrName.length; j++) {
880 Node key_attrNode = attrMap.getNamedItem(key_attrName[j]);
881 if (key_attrNode != null) {
882 keys[j] = key_attrNode.getNodeValue().trim();
883 }
884 }
885 if (!keys[0].equals("")) {
886
887 String value = "";
888 Node val_attrNode = attrMap.getNamedItem(val_attrName);
889 if (val_attrNode != null) {
890 value = val_attrNode.getNodeValue().trim();
891 }
892 result.put(keys, value);
893 }
894 }
895 }
896
897 return result;
898 }
899
900 /***
901 * Given a node name, return all child nodes' name-value pairs into a
902 * hashtable. Node names are hashkeys, node String values are hashvalues.
903 *
904 * @return Hashtable. Node names are hashkeys, node String values are
905 * hashvalues.
906 * @since 1.0
907 */
908 public Hashtable getChildNodeHashValues(String nodeName) throws XMLUtilException {
909 Vector vTag = _getNodesByString(_configElem, nodeName);
910 if (vTag == null ) {
911 String msg = "***Error: No such node: " + nodeName;
912 throw new XMLUtilException(msg);
913 }
914
915 if (vTag.size() == 0) {
916 return null;
917 }
918
919 Hashtable result = new Hashtable();
920
921 Node node = (Node)vTag.elementAt(0);
922 NodeList children = node.getChildNodes();
923
924 for(int i=0; i<children.getLength(); i++) {
925 Node child = children.item(i);
926 String name = child.getNodeName();
927 String value = "";
928 if(child.getNodeType() == Node.ELEMENT_NODE) {
929 if(child.hasChildNodes()) {
930 Node aNode = child.getFirstChild();
931 if(aNode != null && aNode.getNodeType() == Node.TEXT_NODE) {
932 value = aNode.getNodeValue().trim();
933 }
934 }
935 result.put(name, value);
936 }
937 }
938
939 return result;
940 }
941
942
943 /***
944 * Loading XML file to DOM tree.
945 * It first tries to get file location from absolute path,
946 * if not found, then search from classpath (relative path).
947 * During load the XML file is validated. The validation
948 * can be switched off by providing the system property
949 * "xmlutil.script.validation=false"
950 * @param fileName Name of XML file
951 * @throws XMLUtilException
952 */
953 private void _init(String fileName) throws XMLUtilException {
954 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
955 String validate = System.getProperty("xmlutil.script.validation");
956 if (validate != null && validate.compareTo("false") == 0) {
957 factory.setValidating(false);
958 } else {
959 factory.setValidating(true);
960 if (System.getProperty("xmlutil.parser.version") != null && System.getProperty("xmlutil.parser.version").compareTo("Xerces2") == 0) {
961 factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
962 }
963 }
964 factory.setNamespaceAware(true);
965
966 DocumentBuilder domBuilder = null;
967 try {
968 domBuilder = factory.newDocumentBuilder();
969 } catch (ParserConfigurationException e) {
970 String msg = "***Error: " + e.getMessage();
971 throw new XMLUtilException(msg);
972 }
973 SAXErrorHandlerImpl error = new SAXErrorHandlerImpl();
974 domBuilder.setErrorHandler(error);
975
976 Document configDOM = null;
977
978 try {
979 InputStream is = new FileInputStream(fileName);
980 configDOM = domBuilder.parse(is);
981 is.close();
982 } catch (FileNotFoundException e) {
983
984 } catch (IOException e) {
985 String msg = "***Error: " + e.getMessage();
986 throw new XMLUtilException(msg);
987 } catch (SAXException e) {
988 String msg = "***Error: " + e.getMessage();
989 throw new XMLUtilException(msg);
990 }
991
992 if (configDOM == null) {
993 InputStream is = getClass().getClassLoader().getResourceAsStream( fileName );
994
995 if ( is == null ) {
996 String msg = "***Error: " + fileName + " is missing";
997 throw new XMLUtilException(msg);
998 }
999
1000
1001 error.clearErrors();
1002 try {
1003 configDOM = domBuilder.parse(is);
1004 is.close();
1005 } catch (FileNotFoundException e) {
1006
1007 } catch (IOException e) {
1008 String msg = "***Error: " + e.getMessage();
1009 throw new XMLUtilException(msg);
1010 } catch (SAXException e) {
1011 String msg = "***Error: " + e.getMessage();
1012 throw new XMLUtilException(msg);
1013 }
1014 }
1015
1016 if (configDOM == null) {
1017 String msg = "***Error: DOM tree is null. Please verify if " + fileName + " is under either absolute path or classpath.";
1018 throw new XMLUtilException(msg);
1019 }
1020
1021 if (!configDOM.isSupported("Traversal", "2.0")) {
1022 String msg = "***Error: This DOM Document does not support Traversal. This might be caused by the fact that the XML parser does not support Traversal. Use a more recent parser (e.g. Xerces 1.4.4 or higher).";
1023 throw new XMLUtilException(msg);
1024 }
1025
1026 if ((error.getErrors()).size() > 0) {
1027 String msg = "***Error: xml file " + fileName + " is INVALID! ";
1028 throw new XMLUtilException(msg);
1029 }
1030
1031 _configElem = configDOM.getDocumentElement();
1032
1033 }
1034
1035
1036 /***
1037 * Recursive function <p>
1038 * Start from given Element, search all nodes that fits given path.
1039 * @return Vector of nodes.
1040 */
1041 private Vector _getNodesByString(Element elem, String path) {
1042 Vector vTag = XStringParser.parseXString(path);
1043 Vector vNode = new Vector();
1044 String tmpPath = path;
1045
1046 if(vTag.size() == 0) {
1047 return null;
1048 }
1049
1050
1051 if(vTag.size() == 1) {
1052 if((elem.getTagName()).equals((String)vTag.elementAt(0))) {
1053 vNode.addElement((Node)elem);
1054 }
1055 return vNode;
1056 }
1057
1058 int index = tmpPath.indexOf(XStringParser.getPathToken(), 1);
1059 if (index == -1) {
1060 return null;
1061 }
1062 tmpPath = tmpPath.substring(index + 1);
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075 NodeList childNodes = elem.getChildNodes();
1076 if (childNodes == null)
1077 return null;
1078
1079 for (int i=0; i<childNodes.getLength(); i++) {
1080 Node child = childNodes.item(i);
1081 if(child.getNodeType() == Node.ELEMENT_NODE) {
1082 String tagName = ((Element)child).getTagName();
1083 if (tagName.equals((String)vTag.elementAt(1))) {
1084 Vector vTmp = _getNodesByString((Element)childNodes.item(i), tmpPath);
1085
1086 if (vTmp.size() != 0) {
1087 vNode.addAll(vTmp);
1088 }
1089 }
1090 }
1091 }
1092
1093 return vNode;
1094 }
1095
1096
1097 /***
1098 * Constructor: constructing internal element from Node object.
1099 * This Node object must be either DOCUMENT_NODE or ELEMENT_NODE type
1100 * @since 1.0
1101 */
1102 public XMLUtil(Node node) throws XMLUtilException {
1103 if(node.getNodeType() == Node.DOCUMENT_NODE) {
1104 _configElem = ((Document)node).getDocumentElement();
1105 } else if (node.getNodeType() == Node.ELEMENT_NODE) {
1106 _configElem = (Element)node;
1107 } else {
1108 throw new XMLUtilException("***Error: Error constructing XMLUtil instance. Node is neither Document nor Element type.");
1109 }
1110 }
1111
1112
1113 /***
1114 * Constructor: constructing internal element from XML file
1115 * @since 1.0
1116 */
1117 public XMLUtil(String fileName) throws XMLUtilException {
1118 _init(fileName);
1119 }
1120
1121 private Element _configElem;
1122
1123 }
1124