View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.support.xml;
14  
15  import java.io.IOException;
16  import java.io.InputStream;
17  import java.io.OutputStreamWriter;
18  import java.io.StringReader;
19  import java.io.StringWriter;
20  import java.io.Writer;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.StringTokenizer;
30  
31  import javax.xml.namespace.QName;
32  import javax.xml.parsers.DocumentBuilder;
33  import javax.xml.parsers.DocumentBuilderFactory;
34  import javax.xml.parsers.ParserConfigurationException;
35  import javax.xml.transform.TransformerException;
36  
37  import org.apache.log4j.Logger;
38  import org.apache.xmlbeans.XmlCursor;
39  import org.apache.xmlbeans.XmlException;
40  import org.apache.xmlbeans.XmlObject;
41  import org.apache.xmlbeans.XmlOptions;
42  import org.w3c.dom.Attr;
43  import org.w3c.dom.Document;
44  import org.w3c.dom.DocumentFragment;
45  import org.w3c.dom.Element;
46  import org.w3c.dom.NamedNodeMap;
47  import org.w3c.dom.Node;
48  import org.w3c.dom.NodeList;
49  import org.w3c.dom.Text;
50  import org.w3c.dom.traversal.DocumentTraversal;
51  import org.w3c.dom.traversal.NodeFilter;
52  import org.w3c.dom.traversal.TreeWalker;
53  import org.xml.sax.InputSource;
54  import org.xml.sax.SAXException;
55  
56  import com.eviware.soapui.impl.wsdl.WsdlInterface;
57  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
58  import com.eviware.soapui.support.types.StringToStringMap;
59  import com.sun.org.apache.xpath.internal.XPathAPI;
60  
61  /***
62   * General XML-related utilities
63   */
64  
65  public final class XmlUtils
66  {
67     private static DocumentBuilder documentBuilder;
68     private final static Logger log = Logger.getLogger( XmlUtils.class );
69  
70     static public Document parse( InputStream in )
71     {
72        try
73        {
74           return ensureDocumentBuilder().parse( in );
75        }
76        catch( Exception e )
77        {
78        	log.error( "Error parsing InputStream; " + e.getMessage(), e );
79        }
80  
81        return null;
82     }
83  
84     static public Document parse( String fileName ) throws IOException
85     {
86        try
87        {
88           return  ensureDocumentBuilder().parse( fileName );
89        }
90        catch( SAXException e )
91        {
92        	log.error( "Error parsing fileName [" + fileName + "]; " + e.getMessage(), e );
93        }
94  
95        return null;
96     }
97     
98     public static String entitize( String xml )
99     {
100    	return xml.replaceAll( "&", "&amp;" ).replaceAll( "<", "&lt;" ).replaceAll( ">", "&gt;" ).
101    		replaceAll( "\"", "&quot;" ).replaceAll( "'", "&apos;" );
102    }
103 
104    static public Document parse( InputSource inputSource ) throws IOException
105    {
106       try
107       {
108          return ensureDocumentBuilder().parse( inputSource );
109       }
110       catch( SAXException e )
111       {
112       	throw new IOException( e.toString() );
113       }
114    }
115 
116    private static DocumentBuilder ensureDocumentBuilder()
117    {
118       if( documentBuilder == null )
119       {
120          try
121          {
122             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
123             dbf.setNamespaceAware( true );
124 				documentBuilder = dbf.newDocumentBuilder();
125          }
126          catch( ParserConfigurationException e )
127          {
128          	log.error( "Error creating DocumentBuilder; " + e.getMessage() );
129          }
130       }
131 
132       return documentBuilder;
133    }
134 
135    public static void serializePretty( Document document )
136    {
137       try
138       {
139          serializePretty( document, new OutputStreamWriter( System.out ) );
140       }
141       catch( IOException e )
142       {
143          log.error( "Failed to seraialize: " + e );
144       }
145    }
146 
147    public static void serializePretty( Document dom, Writer writer )
148       throws IOException
149    {
150    	try
151 		{
152 			XmlObject xmlObject = XmlObject.Factory.parse(dom.getDocumentElement());
153 			serializePretty(xmlObject, writer);
154 		}
155 		catch (XmlException e)
156 		{
157 			throw new IOException( e.toString() );
158 		}
159    }
160    
161    public static void serializePretty( XmlObject xmlObject, Writer writer ) throws IOException
162 	{
163 		XmlOptions options = new XmlOptions();
164 		options.setSavePrettyPrint();
165 		options.setSavePrettyPrintIndent( 3 );
166 		options.setSaveNoXmlDecl();
167 		options.setSaveAggressiveNamespaces();
168 		xmlObject.save(writer, options);
169 	}
170 
171    public static void serialize( Document dom, Writer writer )
172    throws IOException
173 	{
174    	serialize( dom.getDocumentElement(), writer );
175 	}
176    
177    public static void serialize( Element elm, Writer writer )
178    throws IOException
179 	{
180    	try
181 		{
182 			XmlObject xmlObject = XmlObject.Factory.parse(elm);
183 			xmlObject.save( writer );
184 		}
185 		catch (XmlException e)
186 		{
187 			throw new IOException( e.toString() );
188 		}
189 	}
190    
191    static public void setElementText( Element elm, String text )
192    {
193       Node node = elm.getFirstChild();
194       if( node == null  )
195       {
196       	if( text != null)
197       		elm.appendChild( elm.getOwnerDocument().createTextNode( text ) );
198       }
199       else if( node.getNodeType() == Node.TEXT_NODE )
200       {
201          if( text == null )
202             node.getParentNode().removeChild( node );
203          else
204             node.setNodeValue( text );
205       }
206       else if( text != null )
207       {
208          Text textNode = node.getOwnerDocument().createTextNode( text );
209          elm.insertBefore( textNode, elm.getFirstChild() );
210       }
211    }
212 
213    public static String getChildElementText( Element elm, String name )
214    {
215       Element child = getFirstChildElement( elm, name );
216       return child == null ? null : getElementText( child );
217    }
218 
219    public static Element getFirstChildElement( Element elm )
220    {
221    	return getFirstChildElement( elm, null );
222    }
223    
224    public static Element getFirstChildElement( Element elm, String name )
225    {
226       NodeList nl = elm.getChildNodes();
227       for( int c = 0; c < nl.getLength(); c++ )
228       {
229          Node node = nl.item( c );
230          if( node.getNodeType() == Node.ELEMENT_NODE && (name == null || node.getNodeName().equals( name )) )
231             return (Element) node;
232       }
233 
234       return null;
235    }
236    
237    public static Element getFirstChildElementNS( Element elm, String tns, String localName )
238    {
239    	if( tns == null && localName == null )
240    		return getFirstChildElement( elm );
241    	
242    	if( tns == null )
243    		return getFirstChildElement( elm, localName );
244    	
245       NodeList nl = elm.getChildNodes();
246       for( int c = 0; c < nl.getLength(); c++ )
247       {
248          Node node = nl.item( c );
249          if( node.getNodeType() != Node.ELEMENT_NODE ) continue;
250          
251          if( localName == null && tns.equals( node.getNamespaceURI() ))
252          	return ( Element ) node;
253          
254          if( localName != null && tns.equals( node.getNamespaceURI() ) && localName.equals( node.getLocalName() ))
255          	return ( Element ) node;
256       }
257 
258       return null;
259    }
260 
261    static public String getElementText( Element elm )
262    {
263       Node node = elm.getFirstChild();
264       if( node != null && node.getNodeType() == Node.TEXT_NODE )
265          return node.getNodeValue();
266 
267       return null;
268    }
269    
270    static public String getFragmentText( DocumentFragment elm )
271    {
272       Node node = elm.getFirstChild();
273       if( node != null && node.getNodeType() == Node.TEXT_NODE )
274          return node.getNodeValue();
275 
276       return null;
277    }
278 
279    public static String getChildElementText( Element elm, String name, String defaultValue )
280    {
281       String result = getChildElementText( elm, name );
282       return result == null ? defaultValue : result;
283    }
284 
285    static public String getNodeValue( Node node )
286    {
287    	if( node.getNodeType() == Node.ELEMENT_NODE )
288    		return getElementText( (Element) node );
289    	else if( node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE )
290    		return getFragmentText( (DocumentFragment) node );
291    	else 
292    		return node.getNodeValue();
293    }
294 
295    public static Node createNodeFromPath( Element modelElement, String path )
296    {
297       Document document = modelElement.getOwnerDocument();
298       StringTokenizer st = new StringTokenizer( path, "/" );
299       while( st.hasMoreTokens() )
300       {
301          String t = st.nextToken();
302 
303          if( st.hasMoreTokens() )
304          {
305             if( t.equals( ".." ) )
306             {
307                modelElement = (Element) modelElement.getParentNode();
308             }
309             else
310             {
311                Element elm = getFirstChildElement( modelElement, t );
312                if( elm == null )
313                   modelElement = (Element) modelElement.insertBefore(
314                      document.createElement( t ),
315                      getFirstChildElement( modelElement, t ) );
316                else
317                   modelElement = elm;
318             }
319          }
320          else
321          {
322             modelElement = (Element) modelElement.insertBefore(
323                document.createElement( t ),
324                getFirstChildElement( modelElement, t ) );
325          }
326       }
327 
328       return modelElement;
329    }
330 
331    public static Element addChildElement( Element element, String name, String text )
332    {
333       Document document = element.getOwnerDocument();
334       Element result = (Element) element.appendChild( document.createElement( name ) );
335       if( text != null )
336          result.appendChild( document.createTextNode( text ) );
337 
338       return result;
339    }
340 
341    public static void setChildElementText( Element element, String name, String text )
342    {
343       Element elm = getFirstChildElement( element, name );
344       if( elm == null )
345       {
346          elm = element.getOwnerDocument().createElement( name );
347          element.appendChild( elm );
348       }
349 
350       setElementText( elm, text );
351    }
352 
353    public static Document parseXml( String xmlString ) throws IOException
354    {
355       return parse( new InputSource( new StringReader( xmlString )));
356    }
357    
358    public static void dumpParserErrors(XmlObject xmlObject)
359    {
360       List errors = new ArrayList();
361       xmlObject.validate(new XmlOptions().setErrorListener(errors));
362       for (Iterator i = errors.iterator(); i.hasNext();)
363       {
364          System.out.println(i.next());
365       }
366    }
367 
368 	public static String transferValues(String source, String dest)
369 	{
370 		try
371 		{
372 			Document sourceDom = parseXml(source);
373 			Document destDom = parseXml(dest);
374 			
375 			TreeWalker walker = ((DocumentTraversal)sourceDom).createTreeWalker( sourceDom.getDocumentElement(),
376 					NodeFilter.SHOW_ELEMENT, null, true );
377 			
378 			Element elm = (Element) walker.nextNode();
379 			while( elm != null )
380 			{
381 				String path = getElementPath( elm );
382 				Node nsNode = getNSNode( elm );
383 				Element elm2 = (Element) XPathAPI.selectSingleNode( destDom.getDocumentElement(), path, nsNode );
384 				if( elm2 != null )
385 				{
386 					// transfer attributes
387 					NamedNodeMap attributes = elm.getAttributes();
388 					for( int c = 0; c < attributes.getLength(); c++ )
389 					{
390 						Attr attr = (Attr) attributes.item( c );
391 						elm2.setAttribute( attr.getNodeName(), attr.getNodeValue() );
392 					}
393 					
394 					// transfer text
395 					setElementText( elm2, getElementText( elm ));
396 				}
397 				
398 				elm = (Element) walker.nextNode();
399 			}
400 
401 			StringWriter writer = new StringWriter();
402 			serialize( destDom, writer );
403 			return writer.toString();
404 		}
405 		catch (TransformerException e)
406 		{
407 			e.printStackTrace();
408 		}
409 		catch (IOException e)
410 		{
411 			e.printStackTrace();
412 		}
413 		
414 		return dest;
415 	}
416 
417 	private static Node getNSNode(Node elm)
418 	{
419 		Element result = elm.getOwnerDocument().createElement("nsnode");
420 		
421 		while( elm != null )
422 		{
423 			NamedNodeMap attributes = elm.getAttributes();
424 			if( attributes != null )
425 			{
426 				for( int c = 0; c < attributes.getLength(); c++ )
427 				{
428 					Node attr = attributes.item( c );
429 					if( attr.getNodeName().startsWith( "xmlns:" ) || attr.getNodeName().equals( "xmlns") )
430 					{
431 						result.setAttribute( attr.getNodeName(), attr.getNodeValue() );
432 					}
433 				}
434 			}
435 			
436 			elm = elm.getParentNode();
437 		}
438 		
439 		return result;
440 	}
441 
442 	/***
443 	 * Returns absolute xpath for specified element, ignores namespaces
444 	 *  
445 	 * @param elm the element to create for
446 	 * @return the elements path in its containing document
447 	 */
448 	
449 	public static String getElementPath(Element element)
450 	{
451 		Node elm = element;
452 		
453 		String result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]";
454 		while( elm.getParentNode() != null && elm.getParentNode().getNodeType() != Node.DOCUMENT_NODE )
455 		{
456 			elm = elm.getParentNode();
457 			result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]/" + result;
458 		}
459 
460 		return "/" + result;
461 	}
462 
463 	/***
464 	 * Gets the index of the specified element amongst elements with the same name
465 	 * 
466 	 * @param element the element to get for
467 	 * @return the index of the element, will be >= 1
468 	 */
469 	
470 	public static int getElementIndex(Node element)
471 	{
472 		int result = 1;
473 		
474 		Node elm = element.getPreviousSibling();
475 		while( elm != null )
476 		{
477 			if( elm.getNodeType() == Node.ELEMENT_NODE && elm.getNodeName().equals( element.getNodeName() ))
478 				result++;
479 			elm = elm.getPreviousSibling();
480 		}
481 		
482 		return result;	
483 	}
484 	
485 	public static String declareXPathNamespaces( String xmlString ) throws XmlException
486 	{
487 		return declareXPathNamespaces( XmlObject.Factory.parse(xmlString));
488 	}
489 	
490 	public static synchronized String prettyPrintXml( String xml )
491 	{
492       try
493       {
494       	if( xml == null )
495       		return null;
496       	
497          StringWriter writer = new StringWriter();
498          XmlUtils.serializePretty( XmlObject.Factory.parse( xml ), writer );
499          return writer.toString();
500       }
501       catch( Exception e )
502       {
503       	log.warn( "Failed to prettyPrint xml: " + e );
504          return xml;
505       }
506 	}
507 	
508 	public static synchronized String prettyPrintXml( XmlObject xml )
509 	{
510       try
511       {
512       	if( xml == null )
513       		return null;
514       	
515          StringWriter writer = new StringWriter();
516          XmlUtils.serializePretty( xml, writer );
517          return writer.toString();
518       }
519       catch( Exception e )
520       {
521       	log.warn( "Failed to prettyPrint xml: " + e );
522          return xml.xmlText();
523       }
524 	}
525 
526 	public static String declareXPathNamespaces(WsdlInterface iface)
527 	{
528 		StringBuffer buf = new StringBuffer();
529 		buf.append( "declare namespace soap='" );
530 		buf.append( iface.getSoapVersion().getEnvelopeNamespace() );
531 		buf.append( "';\n");
532 		
533 		try
534 		{
535 			Collection<String> namespaces = iface.getWsdlContext().getDefinedNamespaces();
536 			int c = 1;
537 			for (Iterator<String> i = namespaces.iterator(); i.hasNext();)
538 			{
539 				buf.append("declare namespace ns");
540 				buf.append(c++);
541 				buf.append("='");
542 				buf.append(i.next());
543 				buf.append("';\n");
544 			}
545 		}
546 		catch (Exception e)
547 		{
548 			e.printStackTrace();
549 		}		
550 		
551 		return buf.toString();
552 	}
553 	
554 	public static String createXPath(Node node )
555 	{
556 		return createXPath( node, false, false, null );
557 	}
558 	
559 	public static String createXPath(Node node, boolean anonymous, boolean selectText, XPathModifier modifier )
560 	{
561 		StringToStringMap nsMap = new StringToStringMap();
562 		int nsCnt = 1;
563 		List<String> pathComponents = new ArrayList<String>();
564 		
565 		String namespaceURI = node.getNamespaceURI();
566 		if( node.getNodeType() == Node.ATTRIBUTE_NODE )
567 		{
568 			if( namespaceURI.length() > 0 )
569 			{
570 				String prefix = node.getPrefix();
571 				if( prefix == null || prefix.length() == 0 )
572 					prefix = "ns" + nsCnt++;
573 				
574 				nsMap.put( namespaceURI, prefix );
575 				pathComponents.add( "@" + prefix + ":" + node.getLocalName() );
576 			}
577 			else
578 			{
579 				pathComponents.add( "@" + node.getLocalName() );
580 			}
581 			node = ((Attr)node).getOwnerElement();
582 		}
583 		
584 		if( node.getNodeType() == Node.ELEMENT_NODE )
585 		{
586 			int index = anonymous ? 0 : findNodeIndex( node );
587 			
588 			String pc = null;
589 		
590 			namespaceURI = node.getNamespaceURI();
591 			if( namespaceURI.length() > 0 )
592 			{
593 				String prefix = node.getPrefix();
594 				if( prefix == null || prefix.length() == 0 )
595 					prefix = "ns" + nsCnt++;
596 				
597 				nsMap.put( namespaceURI, prefix );
598 				pc = prefix + ":" + node.getLocalName();
599 			}
600 			else
601 			{
602 				pc = node.getLocalName();
603 			}
604 			
605 			String elementText = XmlUtils.getElementText( (Element) node );
606 			
607 			// not an attribute?
608 			if( selectText && pathComponents.isEmpty() && elementText != null && elementText.trim().length() > 0  )
609 				pathComponents.add( "text()" );
610 			
611 			pathComponents.add( pc + ((index == 0 ) ? "" : "[" + index + "]" ));
612 		}
613 		else
614 			return null;
615 		
616 		node = node.getParentNode();
617 		namespaceURI = node.getNamespaceURI();
618 		while( node != null && node.getNodeType() == Node.ELEMENT_NODE && 
619 				!node.getNodeName().equals( "Body" ) && 
620 				!namespaceURI.equals( SoapVersion.Soap11.getEnvelopeNamespace() ) &&
621 				!namespaceURI.equals( SoapVersion.Soap12.getEnvelopeNamespace() ))
622 		{
623 			int index = anonymous ? 0 : findNodeIndex( node );
624 			
625 			String ns = nsMap.get( namespaceURI );
626 			String pc = null;
627 			
628 			if( ns == null && namespaceURI.length() > 0 )
629 			{
630 				String prefix = node.getPrefix();
631 				if( prefix == null || prefix.length() == 0 )
632 					prefix = "ns" + nsCnt++;
633 				
634 				nsMap.put( namespaceURI, prefix );
635 				ns = nsMap.get( namespaceURI );
636 				
637 				pc = prefix + ":" + node.getLocalName();
638 			}
639 			else if( ns != null ) 
640 			{
641 				 pc = ns + ":" + node.getLocalName();
642 			}
643 			else
644 			{
645 				 pc = node.getLocalName();
646 			}
647 			
648 			pathComponents.add( pc + ((index == 0 ) ? "" : "[" + index + "]" ));
649 			node = node.getParentNode();
650 			namespaceURI = node.getNamespaceURI();
651 		}
652 		
653 		StringBuffer xpath = new StringBuffer();
654 
655 		for( Iterator<String> i = nsMap.keySet().iterator(); i.hasNext(); )
656 		{
657 			String ns = i.next();
658 			xpath.append( "declare namespace " + nsMap.get( ns ) + "='" + ns + "';\n");
659 		}
660 		
661 		if( modifier != null )
662 			modifier.beforeSelector( xpath );
663 		
664 		xpath.append( "/" );
665 		
666 		for( int c = pathComponents.size()-1; c >= 0; c-- )
667 		{
668 			xpath.append( "/" ).append( pathComponents.get( c ));
669 		}
670 		
671 		if( modifier != null )
672 			modifier.afterSelector( xpath );
673 		
674 		return xpath.toString();
675 	}
676 
677 	private static int findNodeIndex(Node node)
678 	{
679 		String nm = node.getLocalName();
680 		String ns = node.getNamespaceURI();
681 		
682 		Node parentNode = node.getParentNode();
683 		if( parentNode.getNodeType() != Node.ELEMENT_NODE )
684 			return 1;
685 		
686 		NodeList nl = ((Element)parentNode).getElementsByTagNameNS( ns, nm );
687 		
688 		if( nl.getLength() == 1 )
689 			return 0;
690 		
691 		for( int c = 0; c < nl.getLength(); c++ )
692 			if( nl.item( c ) == node )
693 				return c+1;
694 		
695 		throw new RuntimeException( "Child node not found in parent!?" );
696 	}
697 
698 	public static boolean setNodeValue( Node domNode, String string )
699 	{
700 		short nodeType = domNode.getNodeType();
701 		if( nodeType == Node.ELEMENT_NODE )
702 		{
703 			setElementText( ( Element ) domNode, string );
704 			return true;
705 		}
706 		else if( nodeType == Node.ATTRIBUTE_NODE || nodeType == Node.TEXT_NODE )
707 		{
708 			domNode.setNodeValue( string );
709 			return true;
710 		}
711 		
712 		return false;
713 	}
714 
715 	public static String declareXPathNamespaces( XmlObject xmlObject )
716 	{
717 		Map<QName,String> map = new HashMap<QName,String>();
718 		XmlCursor cursor = xmlObject.newCursor();
719 		
720 		while( cursor.hasNextToken() )
721 		{
722 			if( cursor.toNextToken().isNamespace() )
723 				map.put( cursor.getName(), cursor.getTextValue() );
724 		}
725 		
726 		Iterator<QName> i = map.keySet().iterator();
727 		int nsCnt = 0;
728 		
729 		StringBuffer buf = new StringBuffer();
730 		Set<String> prefixes = new HashSet<String>();
731 		Set<String> usedPrefixes = new HashSet<String>();
732 		
733 		while( i.hasNext() )
734 		{
735 			QName name = i.next();
736 			String prefix = name.getLocalPart();
737 			if( prefix.length() == 0 ) prefix = "ns" + Integer.toString( ++nsCnt );
738 			else if( prefix.equals( "xsd") || prefix.equals( "xsi")) continue;
739 			
740 			if( prefixes.contains( prefix ))
741 			{
742 				int c = 1;
743 				while( usedPrefixes.contains( prefix + c )) c++;
744 				
745 				prefix = prefix + Integer.toString( c );
746 			}
747 			else prefixes.add( prefix );
748 			
749 			buf.append( "declare namespace " );
750 			buf.append( prefix );
751 			buf.append( "='" );
752 			buf.append( map.get( name ));
753 			buf.append( "';\n");
754 			
755 			usedPrefixes.add( prefix );
756 		}
757 		
758 		return buf.toString();
759 	}
760 
761 	public static String setXPathContent( String emptyResponse, String string, String actor )
762 	{
763 		try
764 		{
765 			XmlObject xmlObject = XmlObject.Factory.parse( emptyResponse );
766 			XmlObject[] path = xmlObject.selectPath( string );
767 			for( XmlObject xml : path )
768 			{
769 				setNodeValue( xml.getDomNode(), actor );
770 			}
771 			
772 			return xmlObject.toString();
773 		}
774 		catch( XmlException e )
775 		{
776 			e.printStackTrace();
777 		}
778 		
779 		return null;
780 	}
781 	
782 	public static QName getQName( Node node )
783 	{
784 		if( node.getNamespaceURI() == null )
785 			return new QName( node.getNodeName());
786 		else
787 			return new QName( node.getNamespaceURI(), node.getLocalName() );
788 	}
789 
790 	public static String removeXPathNamespaceDeclarations( String xpath )
791 	{
792 		while( xpath.startsWith( "declare namespace" ))
793 		{
794 			int ix = xpath.indexOf( ';' );
795 			if( ix == -1 )
796 				break;
797 			
798 			xpath = xpath.substring( ix+1 ).trim();
799 		}
800 		return xpath;
801 	}
802 
803 	public static String stripWhitespaces( String content )
804 	{
805 		try
806 		{
807 			XmlObject xml = XmlObject.Factory.parse( content, new XmlOptions().setLoadStripWhitespace() );
808 			content = xml.xmlText();
809 		}
810 		catch( XmlException e )
811 		{
812 			e.printStackTrace();
813 		}
814 		
815 		
816 		return content;
817 	}
818 
819 	public static NodeList getChildElements( Element elm )
820 	{
821 		List<Element> list = new ArrayList<Element>();
822 		
823 		NodeList nl = elm.getChildNodes();
824 		for( int c = 0; c < nl.getLength(); c++ )
825 		{
826 			if( nl.item( c ).getNodeType() == Node.ELEMENT_NODE )
827 				list.add(  ( Element ) nl.item( c ) );
828 		}
829 		
830 		return new ElementNodeList( list );
831 	}
832 
833 	private final static class ElementNodeList implements NodeList
834 	{
835 		private final List<Element> list;
836 
837 		public ElementNodeList( List<Element> list )
838 		{
839 			this.list = list;
840 		}
841 
842 		public int getLength()
843 		{
844 			return list.size();
845 		}
846 
847 		public Node item( int index )
848 		{
849 			return list.get( index );
850 		}}
851 
852 	public static boolean seemsToBeXml( String requestContent )
853 	{
854 		try
855 		{
856 			return requestContent != null && XmlObject.Factory.parse( requestContent ) != null;
857 		}
858 		catch( XmlException e )
859 		{
860 			return false;
861 		}
862 	}
863 }
864