001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/framework/xml/XMLTools.java $
002 /*---------------- FILE HEADER ------------------------------------------
003
004 This file is part of deegree.
005 Copyright (C) 2001-2008 by:
006 EXSE, Department of Geography, University of Bonn
007 http://www.giub.uni-bonn.de/deegree/
008 lat/lon GmbH
009 http://www.lat-lon.de
010
011 This library is free software; you can redistribute it and/or
012 modify it under the terms of the GNU Lesser General Public
013 License as published by the Free Software Foundation; either
014 version 2.1 of the License, or (at your option) any later version.
015
016 This library is distributed in the hope that it will be useful,
017 but WITHOUT ANY WARRANTY; without even the implied warranty of
018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019 Lesser General Public License for more details.
020
021 You should have received a copy of the GNU Lesser General Public
022 License along with this library; if not, write to the Free Software
023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024
025 Contact:
026
027 Andreas Poth
028 lat/lon GmbH
029 Aennchenstr. 19
030 53115 Bonn
031 Germany
032 E-Mail: poth@lat-lon.de
033
034 Prof. Dr. Klaus Greve
035 Department of Geography
036 University of Bonn
037 Meckenheimer Allee 166
038 53115 Bonn
039 Germany
040 E-Mail: greve@giub.uni-bonn.de
041
042 ---------------------------------------------------------------------------*/
043
044 package org.deegree.framework.xml;
045
046 import java.io.IOException;
047 import java.io.InputStream;
048 import java.io.InputStreamReader;
049 import java.io.Reader;
050 import java.io.StringReader;
051 import java.net.URI;
052 import java.net.URISyntaxException;
053 import java.util.ArrayList;
054 import java.util.Arrays;
055 import java.util.Iterator;
056 import java.util.List;
057 import java.util.Map;
058
059 import javax.xml.parsers.DocumentBuilder;
060 import javax.xml.parsers.DocumentBuilderFactory;
061 import javax.xml.parsers.ParserConfigurationException;
062
063 import org.deegree.datatypes.QualifiedName;
064 import org.deegree.framework.log.ILogger;
065 import org.deegree.framework.log.LoggerFactory;
066 import org.deegree.framework.util.StringTools;
067 import org.deegree.ogcbase.CommonNamespaces;
068 import org.jaxen.JaxenException;
069 import org.jaxen.XPath;
070 import org.jaxen.dom.DOMXPath;
071 import org.w3c.dom.Attr;
072 import org.w3c.dom.CDATASection;
073 import org.w3c.dom.Comment;
074 import org.w3c.dom.Document;
075 import org.w3c.dom.Element;
076 import org.w3c.dom.NamedNodeMap;
077 import org.w3c.dom.Node;
078 import org.w3c.dom.NodeList;
079 import org.w3c.dom.Text;
080 import org.xml.sax.InputSource;
081 import org.xml.sax.SAXException;
082
083 /**
084 * XML Tools based on JAXP 1.1 for parsing documents and retrieving node values/node attributes.
085 * Furthermore this utility class provides node retrieval based on XPath expressions.
086 *
087 * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
088 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
089 * @author last edited by: $Author: aschmitz $
090 *
091 * @version $Revision: 12137 $, $Date: 2008-06-04 10:28:43 +0200 (Mi, 04 Jun 2008) $
092 */
093 public final class XMLTools {
094
095 private static final ILogger LOG = LoggerFactory.getLogger( XMLTools.class );
096
097 private XMLTools() {
098 // hidden constructor to prevent instantiation
099 }
100
101 // ------------------------------------------------------------------------
102 // XPath based parsing methods
103 // ------------------------------------------------------------------------
104
105 /**
106 * @param contextNode
107 * @param xPathQuery
108 * @param nsContext
109 * @return Node
110 * @throws XMLParsingException
111 */
112 public static Node getNode( Node contextNode, String xPathQuery, NamespaceContext nsContext )
113 throws XMLParsingException {
114 Node node = null;
115 try {
116 XPath xpath = new DOMXPath( xPathQuery );
117 xpath.setNamespaceContext( nsContext );
118 node = (Node) xpath.selectSingleNode( contextNode );
119
120 if ( xPathQuery.endsWith( "text()" ) ) {
121 List<Node> nl = xpath.selectNodes( contextNode );
122 int pos = xPathQuery.lastIndexOf( "/" );
123 if ( pos > 0 ) {
124 xPathQuery = xPathQuery.substring( 0, pos );
125 } else {
126 xPathQuery = ".";
127 }
128 xpath = new DOMXPath( xPathQuery );
129 xpath.setNamespaceContext( nsContext );
130 List<Node> nl_ = xpath.selectNodes( contextNode );
131 List<String> tmp = new ArrayList<String>( nl_.size() );
132 for ( int i = 0; i < nl_.size(); i++ ) {
133 tmp.add( getStringValue( nl_.get( i ) ) );
134 }
135
136 for ( int i = 0; i < nl.size(); i++ ) {
137 try {
138 nl.get( i ).getParentNode().removeChild( nl.get( i ) );
139 } catch ( Exception e ) {
140 // no exception thrown, why catch them?
141 }
142 }
143
144 Document doc = contextNode.getOwnerDocument();
145 for ( int i = 0; i < tmp.size(); i++ ) {
146 Text text = doc.createTextNode( tmp.get( i ) );
147 nl_.get( i ).appendChild( text );
148 node = text;
149 }
150 }
151
152 } catch ( JaxenException e ) {
153 throw new XMLParsingException( "Error evaluating XPath-expression '" + xPathQuery + "' from context node '"
154 + contextNode.getNodeName() + "': " + e.getMessage() );
155 }
156 return node;
157 }
158
159 /**
160 * @param contextNode
161 * @param xpath
162 * @param nsContext
163 * @return the element
164 * @throws XMLParsingException
165 * @throws ClassCastException
166 * if the node was not an element
167 */
168 public static Element getElement( Node contextNode, String xpath, NamespaceContext nsContext )
169 throws XMLParsingException {
170 Node node = getNode( contextNode, xpath, nsContext );
171 return (Element) node;
172 }
173
174 /**
175 * @param contextNode
176 * @param xPathQuery
177 * @param nsContext
178 * @param defaultValue
179 * @return the node's String value
180 * @throws XMLParsingException
181 */
182 public static String getNodeAsString( Node contextNode, String xPathQuery, NamespaceContext nsContext,
183 String defaultValue )
184 throws XMLParsingException {
185
186 String value = defaultValue;
187 Node node = getNode( contextNode, xPathQuery, nsContext );
188
189 if ( node != null ) {
190 value = getStringValue( node );
191 }
192 return value;
193 }
194
195 /**
196 * @param contextNode
197 * @param xPathQuery
198 * @param nsContext
199 * @param defaultValue
200 * @return the node's boolean value
201 * @throws XMLParsingException
202 */
203 public static boolean getNodeAsBoolean( Node contextNode, String xPathQuery, NamespaceContext nsContext,
204 boolean defaultValue )
205 throws XMLParsingException {
206 boolean value = defaultValue;
207 Node node = getNode( contextNode, xPathQuery, nsContext );
208 if ( node != null ) {
209 String stringValue = getStringValue( node );
210
211 if ( "true".equals( stringValue ) || "yes".equals( stringValue ) || "1".equals( stringValue ) ) {
212 value = true;
213 } else if ( "false".equals( stringValue ) || "no".equals( stringValue ) || "0".equals( stringValue ) ) {
214 value = false;
215 } else {
216 throw new XMLParsingException( "XPath-expression '" + xPathQuery + " ' from context node '"
217 + contextNode.getNodeName() + "' has an invalid value ('" + stringValue
218 + "'). Valid values are: 'true', 'yes', '1' " + "'false', 'no' and '0'." );
219 }
220 }
221 return value;
222 }
223
224 /**
225 * @param contextNode
226 * @param xPathQuery
227 * @param nsContext
228 * @param defaultValue
229 * @return the node's integer value
230 * @throws XMLParsingException
231 */
232 public static int getNodeAsInt( Node contextNode, String xPathQuery, NamespaceContext nsContext, int defaultValue )
233 throws XMLParsingException {
234 int value = defaultValue;
235 Node node = getNode( contextNode, xPathQuery, nsContext );
236 if ( node != null ) {
237 String stringValue = getStringValue( node );
238 try {
239 value = Integer.parseInt( stringValue );
240 } catch ( NumberFormatException e ) {
241 throw new XMLParsingException( "Result '" + stringValue + "' of XPath-expression '" + xPathQuery
242 + "' from context node '" + contextNode.getNodeName()
243 + "' does not denote a valid integer value." );
244 }
245 }
246 return value;
247 }
248
249 /**
250 * @param contextNode
251 * @param xPathQuery
252 * @param nsContext
253 * @param defaultValue
254 * @return the node's double value
255 * @throws XMLParsingException
256 */
257 public static double getNodeAsDouble( Node contextNode, String xPathQuery, NamespaceContext nsContext,
258 double defaultValue )
259 throws XMLParsingException {
260 double value = defaultValue;
261 Node node = getNode( contextNode, xPathQuery, nsContext );
262 if ( node != null ) {
263 String stringValue = getStringValue( node );
264 try {
265 value = Double.parseDouble( stringValue );
266 } catch ( NumberFormatException e ) {
267 throw new XMLParsingException( "Result '" + stringValue + "' of XPath-expression '" + xPathQuery
268 + "' from context node '" + contextNode.getNodeName()
269 + "' does not denote a valid double value." );
270 }
271 }
272 return value;
273 }
274
275 /**
276 * @param contextNode
277 * @param xPathQuery
278 * @param nsContext
279 * @param defaultValue
280 * @return the node as URI
281 * @throws XMLParsingException
282 */
283 public static URI getNodeAsURI( Node contextNode, String xPathQuery, NamespaceContext nsContext, URI defaultValue )
284 throws XMLParsingException {
285 URI value = defaultValue;
286 Node node = getNode( contextNode, xPathQuery, nsContext );
287 if ( node != null ) {
288 String stringValue = getStringValue( node );
289 try {
290 value = new URI( stringValue );
291 } catch ( URISyntaxException e ) {
292 throw new XMLParsingException( "Result '" + stringValue + "' of XPath-expression '" + xPathQuery
293 + "' from context node '" + contextNode.getNodeName()
294 + "' does not denote a valid URI." );
295 }
296 }
297 return value;
298 }
299
300 /**
301 * @param contextNode
302 * @param xPathQuery
303 * @param nsContext
304 * @param defaultValue
305 * @return the node as qualified name
306 * @throws XMLParsingException
307 */
308 public static QualifiedName getNodeAsQualifiedName( Node contextNode, String xPathQuery,
309 NamespaceContext nsContext, QualifiedName defaultValue )
310 throws XMLParsingException {
311
312 QualifiedName value = defaultValue;
313 Node node = getNode( contextNode, xPathQuery, nsContext );
314
315 if ( node != null ) {
316 value = getQualifiedNameValue( node );
317 }
318 return value;
319
320 }
321
322 /**
323 * returns a list of nodes matching the passed XPath
324 *
325 * @param contextNode
326 * @param xPathQuery
327 * @param nsContext
328 * @return a list of nodes matching the passed XPath
329 * @throws XMLParsingException
330 */
331 public static List<Node> getNodes( Node contextNode, String xPathQuery, NamespaceContext nsContext )
332 throws XMLParsingException {
333 List<Node> nl = null;
334 try {
335 XPath xpath = new DOMXPath( xPathQuery );
336 xpath.setNamespaceContext( nsContext );
337 nl = xpath.selectNodes( contextNode );
338
339 if ( xPathQuery.endsWith( "text()" ) ) {
340
341 int pos = xPathQuery.lastIndexOf( "/" );
342 if ( pos > 0 ) {
343 xPathQuery = xPathQuery.substring( 0, pos );
344 } else {
345 xPathQuery = ".";
346 }
347 xpath = new DOMXPath( xPathQuery );
348 xpath.setNamespaceContext( nsContext );
349 List<?> nl_ = xpath.selectNodes( contextNode );
350 List<String> tmp = new ArrayList<String>( nl_.size() );
351 for ( int i = 0; i < nl_.size(); i++ ) {
352 tmp.add( getStringValue( (Node) nl_.get( i ) ) );
353 }
354
355 for ( int i = 0; i < nl.size(); i++ ) {
356 try {
357 nl.get( i ).getParentNode().removeChild( nl.get( i ) );
358 } catch ( Exception e ) {
359 // ignored, but why? Nothing is actually thrown here?
360 }
361 }
362
363 nl.clear();
364 Document doc = contextNode.getOwnerDocument();
365 for ( int i = 0; i < tmp.size(); i++ ) {
366 Text text = doc.createTextNode( tmp.get( i ) );
367 ( (Node) nl_.get( i ) ).appendChild( text );
368 nl.add( text );
369 }
370 }
371 } catch ( JaxenException e ) {
372 throw new XMLParsingException( "Error evaluating XPath-expression '" + xPathQuery + "' from context node '"
373 + contextNode.getNodeName() + "': " + e.getMessage(), e );
374 }
375 return nl;
376 }
377
378 /**
379 * @param contextNode
380 * @param xPathQuery
381 * @param nsContext
382 * @return the list of nodes as strings
383 * @throws XMLParsingException
384 */
385 public static String[] getNodesAsStrings( Node contextNode, String xPathQuery, NamespaceContext nsContext )
386 throws XMLParsingException {
387 String[] values = null;
388 List<Node> nl = getNodes( contextNode, xPathQuery, nsContext );
389 if ( nl != null ) {
390 values = new String[nl.size()];
391 for ( int i = 0; i < nl.size(); i++ ) {
392 values[i] = getStringValue( nl.get( i ) );
393 }
394 } else {
395 values = new String[0];
396 }
397 return values;
398 }
399
400 /**
401 * @param contextNode to get the strings from
402 * @param xPathQuery finding the nodes
403 * @param nsContext to find the namespaces from.
404 * @return the list of nodes as strings or an empty list, never <code>null</code>
405 * @throws XMLParsingException
406 */
407 public static List<String> getNodesAsStringList( Node contextNode, String xPathQuery, NamespaceContext nsContext )
408 throws XMLParsingException {
409 List<String> result = new ArrayList<String>();
410 List<Node> nl = getNodes( contextNode, xPathQuery, nsContext );
411 if ( nl != null ) {
412 result = new ArrayList<String>(nl.size());
413 for ( int i = 0; i < nl.size(); i++ ) {
414 result.add( getStringValue( nl.get( i ) ) );
415 }
416 }
417 return result;
418 }
419
420 /**
421 * @param contextNode
422 * @param xPathQuery
423 * @param nsContext
424 * @return the nodes as URIs
425 * @throws XMLParsingException
426 */
427 public static URI[] getNodesAsURIs( Node contextNode, String xPathQuery, NamespaceContext nsContext )
428 throws XMLParsingException {
429 String[] values = getNodesAsStrings( contextNode, xPathQuery, nsContext );
430 URI[] uris = new URI[values.length];
431 for ( int i = 0; i < uris.length; i++ ) {
432 try {
433 uris[i] = new URI( values[i] );
434 } catch ( URISyntaxException e ) {
435 throw new XMLParsingException( "Result '" + values[i] + "' of XPath-expression '" + xPathQuery
436 + "' from context node '" + contextNode.getNodeName()
437 + "' does not denote a valid URI." );
438 }
439 }
440 return uris;
441 }
442
443 /**
444 * @param contextNode
445 * @param xPathQuery
446 * @param nsContext
447 * @return the nodes as qualified names
448 * @throws XMLParsingException
449 */
450 public static QualifiedName[] getNodesAsQualifiedNames( Node contextNode, String xPathQuery,
451 NamespaceContext nsContext )
452 throws XMLParsingException {
453
454 QualifiedName[] values = null;
455 List<Node> nl = getNodes( contextNode, xPathQuery, nsContext );
456 if ( nl != null ) {
457 values = new QualifiedName[nl.size()];
458 for ( int i = 0; i < nl.size(); i++ ) {
459 values[i] = getQualifiedNameValue( nl.get( i ) );
460 }
461 } else {
462 values = new QualifiedName[0];
463 }
464 return values;
465
466 }
467
468 /**
469 * @param contextNode
470 * @param xPathQuery
471 * @param nsContext
472 * @return the node
473 * @throws XMLParsingException
474 */
475 public static Node getRequiredNode( Node contextNode, String xPathQuery, NamespaceContext nsContext )
476 throws XMLParsingException {
477 Node node = getNode( contextNode, xPathQuery, nsContext );
478 if ( node == null ) {
479 throw new XMLParsingException( "XPath-expression '" + xPathQuery + "' from context node '"
480 + contextNode.getNodeName() + "' yields no result!" );
481 }
482 return node;
483 }
484
485 /**
486 * @param contextNode
487 * @param xpath
488 * @param nsContext
489 * @return the element
490 * @throws XMLParsingException
491 * @throws ClassCastException
492 * if the node was not an element
493 */
494 public static Element getRequiredElement( Node contextNode, String xpath, NamespaceContext nsContext )
495 throws XMLParsingException {
496 Node node = getRequiredNode( contextNode, xpath, nsContext );
497 return (Element) node;
498 }
499
500 /**
501 * @param contextNode
502 * @param xPathQuery
503 * @param nsContext
504 * @return the node as string
505 * @throws XMLParsingException
506 */
507 public static String getRequiredNodeAsString( Node contextNode, String xPathQuery, NamespaceContext nsContext )
508 throws XMLParsingException {
509 Node node = getRequiredNode( contextNode, xPathQuery, nsContext );
510 return getStringValue( node );
511 }
512
513 /**
514 * @param contextNode
515 * the parent of the requested node
516 * @param xPathQuery
517 * the node to get out of the dom
518 * @param nsContext
519 * context of the node
520 * @param validValues
521 * the values that are valid for the required node
522 * @return one of the String valid String values
523 * @throws XMLParsingException
524 * if no Node was found or the text of the Node was not present in the given valid
525 * strings.
526 */
527 public static String getRequiredNodeAsString( Node contextNode, String xPathQuery, NamespaceContext nsContext,
528 String[] validValues )
529 throws XMLParsingException {
530 String value = getRequiredNodeAsString( contextNode, xPathQuery, nsContext );
531 boolean found = false;
532 for ( int i = 0; i < validValues.length; i++ ) {
533 if ( value.equals( validValues[i] ) ) {
534 found = true;
535 break;
536 }
537 }
538 if ( !found ) {
539 StringBuffer sb = new StringBuffer( "XPath-expression '" + xPathQuery + " ' from context node '"
540 + contextNode.getNodeName()
541 + "' has an invalid value. Valid values are: " );
542 for ( int i = 0; i < validValues.length; i++ ) {
543 sb.append( "'" ).append( validValues[i] ).append( "'" );
544 if ( i != validValues.length - 1 ) {
545 sb.append( ", " );
546 } else {
547 sb.append( "." );
548 }
549 }
550 throw new XMLParsingException( sb.toString() );
551 }
552 return value;
553 }
554
555 /**
556 * Returns the parts of the targeted node value which are separated by the specified regex.
557 *
558 * @param contextNode
559 * @param xPathQuery
560 * @param nsContext
561 * @param regex
562 * @return the parts of the targeted node value which are separated by the specified regex.
563 * @throws XMLParsingException
564 */
565 public static String[] getRequiredNodeAsStrings( Node contextNode, String xPathQuery, NamespaceContext nsContext,
566 String regex )
567 throws XMLParsingException {
568 Node node = getRequiredNode( contextNode, xPathQuery, nsContext );
569 return StringTools.toArray( getStringValue( node ), regex, false );
570 }
571
572 /**
573 * @param contextNode
574 * @param xPathQuery
575 * @param nsContext
576 * @return the node as boolean
577 * @throws XMLParsingException
578 */
579 public static boolean getRequiredNodeAsBoolean( Node contextNode, String xPathQuery, NamespaceContext nsContext )
580 throws XMLParsingException {
581 boolean value = false;
582 Node node = getRequiredNode( contextNode, xPathQuery, nsContext );
583 String stringValue = getStringValue( node );
584 if ( "true".equals( stringValue ) || "yes".equals( stringValue ) ) {
585 value = true;
586 } else if ( "false".equals( stringValue ) || "no".equals( stringValue ) ) {
587 value = false;
588 } else {
589 throw new XMLParsingException( "XPath-expression '" + xPathQuery + " ' from context node '"
590 + contextNode.getNodeName() + "' has an invalid value ('" + stringValue
591 + "'). Valid values are: 'true', 'yes', 'false' and 'no'." );
592 }
593
594 return value;
595 }
596
597 /**
598 * @param contextNode
599 * @param xPathQuery
600 * @param nsContext
601 * @return the node as integer
602 * @throws XMLParsingException
603 */
604 public static int getRequiredNodeAsInt( Node contextNode, String xPathQuery, NamespaceContext nsContext )
605 throws XMLParsingException {
606
607 int value = 0;
608 String stringValue = getRequiredNodeAsString( contextNode, xPathQuery, nsContext );
609 try {
610 value = Integer.parseInt( stringValue );
611 } catch ( NumberFormatException e ) {
612 throw new XMLParsingException( "Result '" + stringValue + "' of XPath-expression '" + xPathQuery
613 + "' from context node '" + contextNode.getNodeName()
614 + "' does not denote a valid integer value." );
615 }
616 return value;
617 }
618
619 /**
620 * @param contextNode
621 * @param xPathQuery
622 * @param nsContext
623 * @return the node as double
624 * @throws XMLParsingException
625 */
626 public static double getRequiredNodeAsDouble( Node contextNode, String xPathQuery, NamespaceContext nsContext )
627 throws XMLParsingException {
628
629 double value = 0;
630 String stringValue = getRequiredNodeAsString( contextNode, xPathQuery, nsContext );
631 try {
632 value = Double.parseDouble( stringValue );
633 } catch ( NumberFormatException e ) {
634 throw new XMLParsingException( "Result '" + stringValue + "' of XPath-expression '" + xPathQuery
635 + "' from context node '" + contextNode.getNodeName()
636 + "' does not denote a valid double value." );
637 }
638 return value;
639 }
640
641 /**
642 * Returns the parts of the targeted node value which are separated by the specified regex. The
643 * string parts are converted to doubles.
644 *
645 * @param contextNode
646 * @param xPathQuery
647 * @param nsContext
648 * @param regex
649 * @return the parts of the targeted node value which are separated by the specified regex.
650 * @throws XMLParsingException
651 */
652 public static double[] getRequiredNodeAsDoubles( Node contextNode, String xPathQuery, NamespaceContext nsContext,
653 String regex )
654 throws XMLParsingException {
655 String[] parts = getRequiredNodeAsStrings( contextNode, xPathQuery, nsContext, regex );
656 double[] doubles = new double[parts.length];
657 for ( int i = 0; i < parts.length; i++ ) {
658 try {
659 doubles[i] = Double.parseDouble( parts[i] );
660 } catch ( NumberFormatException e ) {
661 throw new XMLParsingException( "Value '" + parts[i] + "' does not denote a valid double value." );
662 }
663 }
664 return doubles;
665 }
666
667 /**
668 * @param contextNode
669 * @param xPathQuery
670 * @param nsContext
671 * @return the node as URI
672 * @throws XMLParsingException
673 */
674 public static URI getRequiredNodeAsURI( Node contextNode, String xPathQuery, NamespaceContext nsContext )
675 throws XMLParsingException {
676
677 URI uri = null;
678 String stringValue = getRequiredNodeAsString( contextNode, xPathQuery, nsContext );
679
680 try {
681 uri = new URI( stringValue );
682 } catch ( URISyntaxException e ) {
683 throw new XMLParsingException( "Result '" + stringValue + "' of XPath-expression '" + xPathQuery
684 + "' from context node '" + contextNode.getNodeName()
685 + "' does not denote a valid URI." );
686 }
687 return uri;
688 }
689
690 /**
691 * @param contextNode
692 * @param xPathQuery
693 * @param nsContext
694 * @return the node as qualified name
695 * @throws XMLParsingException
696 */
697 public static QualifiedName getRequiredNodeAsQualifiedName( Node contextNode, String xPathQuery,
698 NamespaceContext nsContext )
699 throws XMLParsingException {
700 Node node = getRequiredNode( contextNode, xPathQuery, nsContext );
701 return getQualifiedNameValue( node );
702 }
703
704 /**
705 * @param contextNode
706 * @param xPathQuery
707 * @param nsContext
708 * @return the nodes
709 * @throws XMLParsingException
710 */
711 public static List<Node> getRequiredNodes( Node contextNode, String xPathQuery, NamespaceContext nsContext )
712 throws XMLParsingException {
713 List<Node> nl = getNodes( contextNode, xPathQuery, nsContext );
714 if ( nl.size() == 0 ) {
715 throw new XMLParsingException( "XPath-expression: '" + xPathQuery + "' from context node '"
716 + contextNode.getNodeName() + "' does not yield a result." );
717 }
718
719 return nl;
720 }
721
722 /**
723 * @param contextNode
724 * @param xpath
725 * @param nsContext
726 * @return a list of Elements
727 * @throws XMLParsingException
728 * @throws ClassCastException
729 * if the resulting nodes of the xpath are not elements
730 */
731 public static List<Element> getRequiredElements( Node contextNode, String xpath, NamespaceContext nsContext )
732 throws XMLParsingException {
733 List<Node> nodes = getRequiredNodes( contextNode, xpath, nsContext );
734
735 List<Element> list = new ArrayList<Element>( nodes.size() );
736 for ( Node n : nodes ) {
737 list.add( (Element) n );
738 }
739
740 return list;
741 }
742
743 /**
744 * @param contextNode
745 * @param xpath
746 * @param nsContext
747 * @return a list of Elements
748 * @throws XMLParsingException
749 * @throws ClassCastException
750 * if the resulting nodes of the xpath are not elements
751 */
752 public static List<Element> getElements( Node contextNode, String xpath, NamespaceContext nsContext )
753 throws XMLParsingException {
754 List<Node> nodes = getNodes( contextNode, xpath, nsContext );
755
756 List<Element> list = new ArrayList<Element>( nodes.size() );
757 for ( Node n : nodes ) {
758 list.add( (Element) n );
759 }
760
761 return list;
762 }
763
764 /**
765 * Returns the content of the nodes matching the XPathQuery as a String array. At least one node
766 * must match the query otherwise an exception will be thrown.
767 *
768 * @param contextNode
769 * @param xPathQuery
770 * @param nsContext
771 * @return the content of the nodes matching the XPathQuery as a String array.
772 * @throws XMLParsingException
773 */
774 public static String[] getRequiredNodesAsStrings( Node contextNode, String xPathQuery, NamespaceContext nsContext )
775 throws XMLParsingException {
776
777 List<Node> nl = getRequiredNodes( contextNode, xPathQuery, nsContext );
778
779 String[] values = new String[nl.size()];
780 for ( int i = 0; i < nl.size(); i++ ) {
781 values[i] = getStringValue( nl.get( i ) );
782 }
783
784 return values;
785 }
786
787 /**
788 * @param contextNode
789 * @param xPathQuery
790 * @param nsContext
791 * @return the qualified names
792 * @throws XMLParsingException
793 */
794 public static QualifiedName[] getRequiredNodesAsQualifiedNames( Node contextNode, String xPathQuery,
795 NamespaceContext nsContext )
796 throws XMLParsingException {
797
798 List<Node> nl = getRequiredNodes( contextNode, xPathQuery, nsContext );
799
800 QualifiedName[] values = new QualifiedName[nl.size()];
801 for ( int i = 0; i < nl.size(); i++ ) {
802 values[i] = getQualifiedNameValue( nl.get( i ) );
803 }
804
805 return values;
806 }
807
808 /**
809 * @param value
810 * @param validValues
811 * @throws XMLParsingException
812 */
813 public static void checkValue( String value, String[] validValues )
814 throws XMLParsingException {
815 for ( int i = 0; i < validValues.length; i++ ) {
816 if ( validValues[i].equals( value ) ) {
817 return;
818 }
819 }
820 StringBuffer sb = new StringBuffer( "Value '" ).append( value ).append( "' is invalid. Valid values are: " );
821 for ( int i = 0; i < validValues.length; i++ ) {
822 sb.append( "'" ).append( validValues[i] ).append( "'" );
823 if ( i != validValues.length - 1 ) {
824 sb.append( ", " );
825 } else {
826 sb.append( "." );
827 }
828 }
829 throw new XMLParsingException( sb.toString() );
830 }
831
832 // ------------------------------------------------------------------------
833 // Node creation methods
834 // ------------------------------------------------------------------------
835
836 /**
837 * Creates a new <code>Element</code> node from the given parameters and appends it to the
838 * also specified <code>Element</code>.
839 *
840 * @param element
841 * <code>Element</code> that the new <code>Element</code> is appended to
842 * @param namespaceURI
843 * use null for default namespace
844 * @param name
845 * qualified name
846 * @return the appended <code>Element</code> node
847 */
848 public static Element appendElement( Element element, URI namespaceURI, String name ) {
849 return appendElement( element, namespaceURI, name, null );
850 }
851
852 /**
853 * Appends a namespace binding for the specified element that binds the given prefix to the
854 * given namespace using a special attribute: xmlns:prefix=namespace
855 *
856 * @param element
857 * @param prefix
858 * @param namespace
859 */
860 public static void appendNSBinding( Element element, String prefix, URI namespace ) {
861 Attr attribute = element.getOwnerDocument().createAttributeNS( CommonNamespaces.XMLNS.toASCIIString(),
862 CommonNamespaces.XMLNS_PREFIX + ":" + prefix );
863 attribute.setNodeValue( namespace.toASCIIString() );
864 element.getAttributes().setNamedItemNS( attribute );
865 }
866
867 /**
868 * Appends the default namespace binding for the specified element.
869 *
870 * @param element
871 * @param prefix
872 * @param namespace
873 */
874 public static void appendNSDefaultBinding( Element element, URI namespace ) {
875 Attr attribute = element.getOwnerDocument().createAttributeNS( CommonNamespaces.XMLNS.toASCIIString(),
876 CommonNamespaces.XMLNS_PREFIX );
877 attribute.setNodeValue( namespace.toASCIIString() );
878 element.getAttributes().setNamedItemNS( attribute );
879 }
880
881 /**
882 * Appends the given namespace bindings to the specified element.
883 * <p>
884 * NOTE: The prebound prefix "xml" is skipped.
885 *
886 * @param element
887 * @param nsContext
888 */
889 public static void appendNSBindings( Element element, NamespaceContext nsContext ) {
890 Map<String, URI> namespaceMap = nsContext.getNamespaceMap();
891 Iterator<String> prefixIter = namespaceMap.keySet().iterator();
892 while ( prefixIter.hasNext() ) {
893 String prefix = prefixIter.next();
894 if ( !CommonNamespaces.XMLNS_PREFIX.equals( prefix ) ) {
895 URI namespace = namespaceMap.get( prefix );
896 appendNSBinding( element, prefix, namespace );
897 }
898 }
899 }
900
901 // ------------------------------------------------------------------------
902 // String value methods
903 // ------------------------------------------------------------------------
904
905 /**
906 * Returns the text contained in the specified element.
907 *
908 * @param node
909 * current element
910 * @return the textual contents of the element
911 */
912 public static String getStringValue( Node node ) {
913 NodeList children = node.getChildNodes();
914 StringBuffer sb = new StringBuffer( children.getLength() * 500 );
915 if ( node.getNodeValue() != null ) {
916 sb.append( node.getNodeValue().trim() );
917 }
918 if ( node.getNodeType() != Node.ATTRIBUTE_NODE ) {
919 for ( int i = 0; i < children.getLength(); i++ ) {
920 if ( children.item( i ).getNodeType() == Node.TEXT_NODE
921 || children.item( i ).getNodeType() == Node.CDATA_SECTION_NODE ) {
922 sb.append( children.item( i ).getNodeValue() );
923 }
924 }
925 }
926 return sb.toString();
927 }
928
929 /**
930 * Returns the text contained in the specified child element of the given element.
931 *
932 * @param name
933 * name of the child element
934 * @param namespace
935 * namespace of the child element
936 * @param node
937 * current element
938 * @param defaultValue
939 * default value if element is missing
940 * @return the textual contents of the element or the given default value, if missing
941 */
942 public static String getStringValue( String name, URI namespace, Node node, String defaultValue ) {
943
944 String value = defaultValue;
945 Element element = getChildElement( name, namespace, node );
946
947 if ( element != null ) {
948 value = getStringValue( element );
949 }
950 if ( value == null || value.equals( "" ) ) {
951 value = defaultValue;
952 }
953
954 return value;
955 }
956
957 /**
958 * Returns the text contained in the specified child element of the given element.
959 *
960 * @param name
961 * name of the child element
962 * @param namespace
963 * namespace of the child element
964 * @param node
965 * current element
966 * @return the textual contents of the element or null, if it is missing
967 * @throws XMLParsingException
968 * if the specified child element is missing
969 */
970 public static String getRequiredStringValue( String name, URI namespace, Node node )
971 throws XMLParsingException {
972 Element element = getRequiredChildElement( name, namespace, node );
973 return getStringValue( element );
974 }
975
976 /**
977 * Returns the value of the specified node attribute.
978 *
979 * @param name
980 * name of attribute
981 * @param namespaceURI
982 * namespace of attribute
983 * @param node
984 * current element
985 * @return the textual contents of the attribute
986 * @throws XMLParsingException
987 * if specified attribute is missing
988 */
989 public static String getRequiredAttrValue( String name, URI namespaceURI, Node node )
990 throws XMLParsingException {
991
992 String namespace = namespaceURI == null ? null : namespaceURI.toString();
993
994 String value = null;
995 NamedNodeMap atts = node.getAttributes();
996 if ( atts != null ) {
997 Attr attribute = null;
998 if ( namespace == null ) {
999 attribute = (Attr) atts.getNamedItem( name );
1000 } else {
1001 attribute = (Attr) atts.getNamedItemNS( namespace, name );
1002 }
1003
1004 if ( attribute != null ) {
1005 value = attribute.getValue();
1006 }
1007 }
1008 if ( value == null ) {
1009 throw new XMLParsingException( "Required attribute " + name + '(' + namespaceURI + ") of element "
1010 + node.getNodeName() + " is missing." );
1011 }
1012 return value;
1013 }
1014
1015 /**
1016 * Parses the value of the submitted <code>Node</code> as a <code>QualifiedName</code>.
1017 * <p>
1018 * To parse the text contents of an <code>Element</code> node, the actual text node must be
1019 * given, not the <code>Element</code> node itself.
1020 * </p>
1021 *
1022 * @param node
1023 * @return object representation of the element
1024 * @throws XMLParsingException
1025 */
1026 public static QualifiedName getQualifiedNameValue( Node node )
1027 throws XMLParsingException {
1028
1029 String name = node.getNodeValue().trim();
1030 QualifiedName qName = null;
1031 if ( name.indexOf( ':' ) > -1 ) {
1032 String[] tmp = StringTools.toArray( name, ":", false );
1033 try {
1034 qName = new QualifiedName( tmp[0], tmp[1], XMLTools.getNamespaceForPrefix( tmp[0], node ) );
1035 } catch ( URISyntaxException e ) {
1036 throw new XMLParsingException( e.getMessage(), e );
1037 }
1038 } else {
1039 qName = new QualifiedName( name );
1040 }
1041 return qName;
1042 }
1043
1044 /**
1045 * Returns the namespace URI that is bound to a given prefix at a certain node in the DOM tree.
1046 *
1047 * @param prefix
1048 * @param node
1049 * @return namespace URI that is bound to the given prefix, null otherwise
1050 * @throws URISyntaxException
1051 */
1052 public static URI getNamespaceForPrefix( String prefix, Node node )
1053 throws URISyntaxException {
1054 if ( node == null ) {
1055 return null;
1056 }
1057 if ( node.getNodeType() == Node.ELEMENT_NODE ) {
1058 NamedNodeMap nnm = node.getAttributes();
1059 if ( nnm != null ) {
1060 // LOG.logDebug( "(searching namespace for prefix (" + prefix
1061 // + "), resulted in a namedNodeMap for the currentNode: " + node.getNodeName() );
1062 for ( int i = 0; i < nnm.getLength(); i++ ) {
1063 Attr a = (Attr) nnm.item( i );
1064 // LOG.logDebug( "\t(searching namespace for prefix (" + prefix + "), resulted
1065 // in an attribute: "
1066 // + a.getName() );
1067
1068 if ( a.getName().startsWith( "xmlns:" ) && a.getName().endsWith( ':' + prefix ) ) {
1069 return new URI( a.getValue() );
1070 } else if ( prefix == null && a.getName().equals( "xmlns" ) ) {
1071 return new URI( a.getValue() );
1072 }
1073 }
1074 }
1075 } else if ( node.getNodeType() == Node.ATTRIBUTE_NODE ) {
1076 return getNamespaceForPrefix( prefix, ( (Attr) node ).getOwnerElement() );
1077 }
1078 return getNamespaceForPrefix( prefix, node.getParentNode() );
1079 }
1080
1081 // ------------------------------------------------------------------------
1082 // Old code - deprecated
1083 // ------------------------------------------------------------------------
1084
1085 /**
1086 * Returns the specified child element of the given element. If there is more than one element
1087 * with that name, the first one is returned.
1088 *
1089 * @deprecated
1090 * @param name
1091 * name of the child element
1092 * @param namespaceURI
1093 * namespaceURI of the child element
1094 * @param node
1095 * current element
1096 * @return the element or null, if it is missing
1097 * @throws XMLParsingException
1098 * if the specified child element is missing
1099 * @throws XMLParsingException
1100 * @todo refactoring required
1101 */
1102 @Deprecated
1103 public static Element getRequiredChildElement( String name, URI namespaceURI, Node node )
1104 throws XMLParsingException {
1105
1106 String namespace = namespaceURI == null ? null : namespaceURI.toString();
1107
1108 NodeList nl = node.getChildNodes();
1109 Element element = null;
1110 Element childElement = null;
1111
1112 if ( ( nl != null ) && ( nl.getLength() > 0 ) ) {
1113 for ( int i = 0; i < nl.getLength(); i++ ) {
1114 if ( nl.item( i ) instanceof Element ) {
1115 element = (Element) nl.item( i );
1116 String s = element.getNamespaceURI();
1117 if ( ( s == null && namespace == null ) || ( namespace != null && namespace.equals( s ) ) ) {
1118 if ( element.getLocalName().equals( name ) ) {
1119 childElement = element;
1120 break;
1121 }
1122 }
1123 }
1124 }
1125 }
1126
1127 if ( childElement == null ) {
1128 throw new XMLParsingException( "Required child-element " + name + '(' + namespaceURI + ") of element "
1129 + node.getNodeName() + " is missing." );
1130 }
1131
1132 return childElement;
1133 }
1134
1135 /**
1136 * Returns the specified child element of the given element. If there is more than one with that
1137 * name, the first one is returned.
1138 *
1139 * @deprecated
1140 * @param name
1141 * name of the child element
1142 * @param namespaceURI
1143 * namespace of the child element
1144 * @param node
1145 * current element
1146 * @return the element or null, if it is missing
1147 * @TODO refactoring required
1148 */
1149 @Deprecated
1150 public static Element getChildElement( String name, URI namespaceURI, Node node ) {
1151
1152 String namespace = namespaceURI == null ? null : namespaceURI.toString();
1153
1154 NodeList nl = node.getChildNodes();
1155 Element element = null;
1156 Element childElement = null;
1157
1158 if ( ( nl != null ) && ( nl.getLength() > 0 ) ) {
1159 for ( int i = 0; i < nl.getLength(); i++ ) {
1160 if ( nl.item( i ) instanceof Element ) {
1161 element = (Element) nl.item( i );
1162 String s = element.getNamespaceURI();
1163 if ( ( s == null && namespace == null ) || ( namespace != null && namespace.equals( s ) ) ) {
1164 if ( element.getLocalName().equals( name ) ) {
1165 childElement = element;
1166 break;
1167 }
1168 }
1169 }
1170 }
1171 }
1172 return childElement;
1173 }
1174
1175 /**
1176 * Returns the specified child elements of the given element.
1177 *
1178 * @deprecated
1179 * @param name
1180 * name of the child elements
1181 * @param namespaceURI
1182 * namespaceURI of the child elements
1183 * @param node
1184 * current element
1185 * @return list of matching child elements
1186 */
1187 @Deprecated
1188 public static ElementList getChildElements( String name, URI namespaceURI, Node node ) {
1189
1190 String namespace = namespaceURI == null ? null : namespaceURI.toString();
1191
1192 NodeList nl = node.getChildNodes();
1193 Element element = null;
1194 ElementList elementList = new ElementList();
1195
1196 if ( ( nl != null ) && ( nl.getLength() > 0 ) ) {
1197 for ( int i = 0; i < nl.getLength(); i++ ) {
1198 if ( nl.item( i ) instanceof Element ) {
1199 element = (Element) nl.item( i );
1200
1201 String s = element.getNamespaceURI();
1202
1203 if ( ( s == null && namespace == null ) || ( namespace != null && namespace.equals( s ) ) ) {
1204 if ( element.getLocalName().equals( name ) ) {
1205 elementList.addElement( element );
1206 }
1207 }
1208 }
1209 }
1210 }
1211 return elementList;
1212 }
1213
1214 /**
1215 *
1216 * Create a new and empty DOM document.
1217 *
1218 * @return a new and empty DOM document.
1219 */
1220 public static Document create() {
1221 return getDocumentBuilder().newDocument();
1222 }
1223
1224 /**
1225 * Create a new document builder with:
1226 * <UL>
1227 * <li>namespace awareness = true
1228 * <li>whitespace ignoring = false
1229 * <li>validating = false
1230 * <li>expandind entity references = false
1231 * </UL>
1232 *
1233 * @return new document builder
1234 */
1235 public static synchronized DocumentBuilder getDocumentBuilder() {
1236 DocumentBuilder builder = null;
1237 try {
1238 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1239 factory.setNamespaceAware( true );
1240 factory.setExpandEntityReferences( false );
1241 factory.setIgnoringElementContentWhitespace( false );
1242 factory.setValidating( false );
1243 try {
1244 factory.setAttribute( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false );
1245 } catch ( IllegalArgumentException _ ) {
1246 // ignore it, we just cannot set the feature
1247 }
1248 builder = factory.newDocumentBuilder();
1249 } catch ( Exception ex ) {
1250 LOG.logError( ex.getMessage(), ex );
1251 }
1252 return builder;
1253 }
1254
1255 /**
1256 * Returns the specified attribute value of the given node.
1257 *
1258 * @param node
1259 * current element
1260 * @param attrName
1261 * local name of the attribute
1262 *
1263 * @return the value of the attribute or null, if it is missing
1264 * @deprecated use
1265 * @see #getAttrValue(Node, URI, String, String) instead
1266 */
1267 @Deprecated
1268 public static String getAttrValue( Node node, String attrName ) {
1269 NamedNodeMap atts = node.getAttributes();
1270 if ( atts == null ) {
1271 return null;
1272 }
1273 Attr a = (Attr) atts.getNamedItem( attrName );
1274 if ( a != null ) {
1275 return a.getValue();
1276 }
1277 return null;
1278 }
1279
1280 /**
1281 * Returns the specified attribute value of the given node.
1282 *
1283 * @param node
1284 * current element
1285 * @param namespaceURI
1286 * namespace of the attribute
1287 * @param attrName
1288 * local name of the attribute
1289 * @param defaultVal
1290 * default value to be returned if attribute is nat available
1291 *
1292 * @return the value of the attribute or null, if it is missing
1293 */
1294 public static String getAttrValue( Node node, URI namespaceURI, String attrName, String defaultVal ) {
1295 if( node == null ){
1296 return null;
1297 }
1298 String namespace = namespaceURI == null ? null : namespaceURI.toString();
1299 NamedNodeMap atts = node.getAttributes();
1300 if ( atts == null ) {
1301 return defaultVal;
1302 }
1303 Attr a = null;
1304 if ( namespace == null ) {
1305 a = (Attr) atts.getNamedItem( attrName );
1306 } else {
1307 a = (Attr) atts.getNamedItemNS( namespace, attrName );
1308 }
1309 if ( a != null ) {
1310 return a.getValue();
1311 }
1312 return defaultVal;
1313 }
1314
1315 /**
1316 * Parses an XML document and returns a DOM object. The underlying input stream is closed at the
1317 * end.
1318 *
1319 * @param reader
1320 * accessing the resource to parse
1321 * @return a DOM object, if en error occurs the response is <code>null</code>
1322 *
1323 * @throws IOException
1324 * @throws SAXException
1325 */
1326 public static Document parse( Reader reader )
1327 throws IOException, SAXException {
1328 javax.xml.parsers.DocumentBuilder parser = null;
1329 Document doc = null;
1330 try {
1331 DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance();
1332 fac.setNamespaceAware( true );
1333 fac.setValidating( false );
1334 fac.setIgnoringElementContentWhitespace( false );
1335 fac.setValidating( false );
1336 try {
1337 fac.setAttribute( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false );
1338 } catch ( IllegalArgumentException _ ) {
1339 // ignore, we just can't set the feature
1340 }
1341 parser = fac.newDocumentBuilder();
1342 doc = parser.parse( new InputSource( reader ) );
1343 } catch ( ParserConfigurationException ex ) {
1344 throw new IOException( "Unable to initialize DocumentBuilder: " + ex.getMessage() );
1345 } catch ( Exception e ) {
1346 throw new SAXException( e.getMessage() );
1347 } finally {
1348 reader.close();
1349 }
1350 return doc;
1351 }
1352
1353 /**
1354 * Parses an XML document and returns a DOM object.
1355 *
1356 * @deprecated
1357 * @param is
1358 * accessing the resource to parse
1359 * @return a DOM object
1360 * @throws IOException
1361 * @throws SAXException
1362 */
1363 @Deprecated
1364 public static Document parse( InputStream is )
1365 throws IOException, SAXException {
1366 return parse( new InputStreamReader( is ) );
1367
1368 }
1369
1370 /**
1371 * Copies one node to another node.
1372 *
1373 * @param source
1374 * @param dest
1375 * @return the copied node
1376 */
1377 public static Node copyNode( Node source, Node dest ) {
1378 if ( source.getNodeType() == Node.TEXT_NODE ) {
1379 Text tn = dest.getOwnerDocument().createTextNode( getStringValue( source ) );
1380 return tn;
1381 }
1382 NamedNodeMap attr = source.getAttributes();
1383 if ( attr != null ) {
1384 for ( int i = 0; i < attr.getLength(); i++ ) {
1385 ( (Element) dest ).setAttribute( attr.item( i ).getNodeName(), attr.item( i ).getNodeValue() );
1386 }
1387 }
1388 NodeList list = source.getChildNodes();
1389 for ( int i = 0; i < list.getLength(); i++ ) {
1390 if ( !( list.item( i ) instanceof Text ) ) {
1391 if ( !( list.item( i ) instanceof Comment ) ) {
1392 Element en = dest.getOwnerDocument().createElementNS( list.item( i ).getNamespaceURI(),
1393 list.item( i ).getNodeName() );
1394 if ( list.item( i ).getNodeValue() != null ) {
1395 en.setNodeValue( list.item( i ).getNodeValue() );
1396 }
1397 Node n = copyNode( list.item( i ), en );
1398 dest.appendChild( n );
1399 }
1400 } else if ( ( list.item( i ) instanceof CDATASection ) ) {
1401 CDATASection cd = dest.getOwnerDocument().createCDATASection( list.item( i ).getNodeValue() );
1402 dest.appendChild( cd );
1403 } else {
1404 Text tn = dest.getOwnerDocument().createTextNode( list.item( i ).getNodeValue() );
1405 dest.appendChild( tn );
1406 }
1407 }
1408 return dest;
1409 }
1410
1411 /**
1412 * Appends a node to an element.
1413 * <p>
1414 * The node can be from the same document or a different one (it is automatically imported, if
1415 * necessary).
1416 *
1417 * @param source
1418 * @param dest
1419 * @return the element that is appended to
1420 */
1421 public static Node insertNodeInto( Node source, Node dest ) {
1422 Node n = dest.getOwnerDocument().importNode( source, true );
1423 dest.appendChild( n );
1424 return dest;
1425 }
1426
1427 /**
1428 * Returns the first child element of the submitted node.
1429 *
1430 * @param node
1431 * @return the first child element of the submitted node.
1432 */
1433 public static Element getFirstChildElement( Node node ) {
1434 NodeList nl = node.getChildNodes();
1435 Element element = null;
1436 if ( ( nl != null ) && ( nl.getLength() > 0 ) ) {
1437 for ( int i = 0; i < nl.getLength(); i++ ) {
1438 if ( nl.item( i ) instanceof Element ) {
1439 element = (Element) nl.item( i );
1440 break;
1441 }
1442 }
1443 }
1444 return element;
1445 }
1446
1447 /**
1448 * @deprecated Returns the first child element of the submitted node that matches the given
1449 * local name.
1450 *
1451 * @param node
1452 * @param name
1453 * @return the child element
1454 */
1455 @Deprecated
1456 public static Element getChildElement( Node node, String name ) {
1457 NodeList nl = node.getChildNodes();
1458 Element element = null;
1459 Element childElement = null;
1460 if ( ( nl != null ) && ( nl.getLength() > 0 ) ) {
1461 for ( int i = 0; i < nl.getLength(); i++ ) {
1462 if ( nl.item( i ) instanceof Element ) {
1463 element = (Element) nl.item( i );
1464
1465 if ( element.getNodeName().equals( name ) ) {
1466 childElement = element;
1467
1468 break;
1469 }
1470 }
1471 }
1472 }
1473 return childElement;
1474 }
1475
1476 /**
1477 * Returns all child elements of the given node.
1478 *
1479 * @param node
1480 * @return all child elements of the given node.
1481 */
1482 public static ElementList getChildElements( Node node ) {
1483 NodeList children = node.getChildNodes();
1484 ElementList list = new ElementList();
1485 for ( int i = 0; i < children.getLength(); i++ ) {
1486 if ( children.item( i ).getNodeType() == Node.ELEMENT_NODE ) {
1487 list.elements.add( (Element) children.item( i ) );
1488 }
1489 }
1490 return list;
1491 }
1492
1493 /**
1494 * sets the value of an existing node
1495 *
1496 * @param target
1497 * @param nodeValue
1498 */
1499 public static void setNodeValue( Element target, String nodeValue ) {
1500 NodeList nl = target.getChildNodes();
1501 for ( int i = 0; i < nl.getLength(); i++ ) {
1502 target.removeChild( nl.item( i ) );
1503 }
1504 Text text = target.getOwnerDocument().createTextNode( nodeValue );
1505 target.appendChild( text );
1506 }
1507
1508 /**
1509 * Creates a new <code>Element</code> node from the given parameters and appends it to the
1510 * also specified <code>Element</code>. Adds a text node to the newly generated
1511 * <code>Element</code> as well.
1512 *
1513 * @param element
1514 * <code>Element</code> that the new <code>Element</code> is appended to
1515 * @param namespaceURI
1516 * use null for default namespace
1517 * @param name
1518 * qualified name
1519 * @param nodeValue
1520 * value for a text node that is appended to the generated element
1521 * @return the appended <code>Element</code> node
1522 */
1523 public static Element appendElement( Element element, URI namespaceURI, String name, String nodeValue ) {
1524 String namespace = namespaceURI == null ? null : namespaceURI.toString();
1525 Element newElement = element.getOwnerDocument().createElementNS( namespace, name );
1526 if ( nodeValue != null && !nodeValue.equals( "" ) )
1527 newElement.appendChild( element.getOwnerDocument().createTextNode( nodeValue ) );
1528 element.appendChild( newElement );
1529 return newElement;
1530 }
1531
1532 /**
1533 * Converts an XML fragment string into a DOM node. The fragment should NOT contain the XML
1534 * prolog. Appends ALL default namespace bindings for ease of use with broken fragments.
1535 *
1536 * @param fragment
1537 * @return a DOM element
1538 * @throws IOException
1539 * @throws SAXException
1540 */
1541 public static Element getStringFragmentAsElement( String fragment )
1542 throws SAXException, IOException {
1543 StringBuffer xml = new StringBuffer( "<?xml version=\"1.0\"?>" );
1544
1545 xml.append( "<bogus " );
1546 // append ALL namespaces
1547 Map<String, URI> map = CommonNamespaces.getNamespaceContext().getNamespaceMap();
1548 for ( String pre : map.keySet() ) {
1549 if(pre.equals("xmlns")){
1550 continue;
1551 }
1552 xml.append( "xmlns:" ).append( pre ).append( "='" );
1553 xml.append( map.get( pre ).toString() ).append( "' " );
1554 }
1555 xml.append( ">" );
1556 xml.append( fragment );
1557 xml.append( "</bogus>" );
1558
1559 StringReader in = new StringReader( xml.toString() );
1560
1561 XMLFragment doc = new XMLFragment( in, "http://www.systemid.org" );
1562 return (Element) doc.getRootElement().getFirstChild();
1563 }
1564
1565 /**
1566 * Works like {@link #getStringFragmentAsElement}, but does not throw exceptions and
1567 * immediately imports the node into another document.
1568 *
1569 * @param fragment
1570 * @param doc
1571 * @return an element in the new document
1572 */
1573 public static Element importStringFragment( String fragment, Document doc ) {
1574 try {
1575 Element e = getStringFragmentAsElement( fragment );
1576 return (Element) doc.importNode( e, true );
1577 } catch ( SAXException e ) {
1578 LOG.logError( "Could not convert String to XML.", e );
1579 } catch ( IOException e ) {
1580 LOG.logError( "Could not convert String to XML.", e );
1581 }
1582
1583 return null;
1584 }
1585
1586 /**
1587 * This method escapes Strings for XML by creating a DOM document, setting the text in an
1588 * attribute, exporting it to text and extracting the escaped string. That means that it's slow,
1589 * and the method of property using DOM to create the XML is a million times better. But if
1590 * you're forced to use StringBuffers, here you have a little helper.
1591 *
1592 * @param str
1593 * @return the escaped string
1594 */
1595 public static String escape( String str ) {
1596 XMLFragment doc = new XMLFragment( new QualifiedName( "dummy" ) );
1597 doc.getRootElement().setAttribute( "dummy", str );
1598 String s = doc.getAsString().substring( 52 );
1599 return s.substring( 0, s.length() - 3 );
1600 }
1601
1602 }