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  
36  import net.sf.saxon.expr.Token;
37  import net.sf.saxon.expr.Tokenizer;
38  
39  import org.apache.log4j.Logger;
40  import org.apache.xmlbeans.XmlCursor;
41  import org.apache.xmlbeans.XmlException;
42  import org.apache.xmlbeans.XmlObject;
43  import org.apache.xmlbeans.XmlOptions;
44  import org.apache.xmlbeans.XmlCursor.TokenType;
45  import org.w3c.dom.Attr;
46  import org.w3c.dom.Document;
47  import org.w3c.dom.DocumentFragment;
48  import org.w3c.dom.Element;
49  import org.w3c.dom.NamedNodeMap;
50  import org.w3c.dom.Node;
51  import org.w3c.dom.NodeList;
52  import org.w3c.dom.Text;
53  import org.xml.sax.InputSource;
54  import org.xml.sax.SAXException;
55  
56  import com.eviware.soapui.SoapUI;
57  import com.eviware.soapui.impl.wsdl.WsdlInterface;
58  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
59  import com.eviware.soapui.support.StringUtils;
60  import com.eviware.soapui.support.types.StringToStringMap;
61  
62  /***
63   * General XML-related utilities
64   */
65  
66  public final class XmlUtils
67  {
68     private static DocumentBuilder documentBuilder;
69     private final static Logger log = Logger.getLogger( XmlUtils.class );
70  
71     static synchronized public Document parse( InputStream in )
72     {
73        try
74        {
75           return ensureDocumentBuilder().parse( in );
76        }
77        catch( Exception e )
78        {
79        	log.error( "Error parsing InputStream; " + e.getMessage(), e );
80        }
81  
82        return null;
83     }
84  
85     static synchronized public Document parse( String fileName ) throws IOException
86     {
87        try
88        {
89           return  ensureDocumentBuilder().parse( fileName );
90        }
91        catch( SAXException e )
92        {
93        	log.error( "Error parsing fileName [" + fileName + "]; " + e.getMessage(), e );
94        }
95  
96        return null;
97     }
98     
99     public static String entitize( String xml )
100    {
101    	return xml.replaceAll( "&", "&amp;" ).replaceAll( "<", "&lt;" ).replaceAll( ">", "&gt;" ).
102    		replaceAll( "\"", "&quot;" ).replaceAll( "'", "&apos;" );
103    }
104 
105    static synchronized public Document parse( InputSource inputSource ) throws IOException
106    {
107       try
108       {
109          return ensureDocumentBuilder().parse( inputSource );
110       }
111       catch( SAXException e )
112       {
113       	throw new IOException( e.toString() );
114       }
115    }
116 
117    private static DocumentBuilder ensureDocumentBuilder()
118    {
119       if( documentBuilder == null )
120       {
121          try
122          {
123             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
124             dbf.setNamespaceAware( true );
125 				documentBuilder = dbf.newDocumentBuilder();
126          }
127          catch( ParserConfigurationException e )
128          {
129          	log.error( "Error creating DocumentBuilder; " + e.getMessage() );
130          }
131       }
132 
133       return documentBuilder;
134    }
135 
136    public static void serializePretty( Document document )
137    {
138       try
139       {
140          serializePretty( document, new OutputStreamWriter( System.out ) );
141       }
142       catch( IOException e )
143       {
144          log.error( "Failed to seraialize: " + e );
145       }
146    }
147 
148    public static void serializePretty( Document dom, Writer writer )
149       throws IOException
150    {
151    	try
152 		{
153 			XmlObject xmlObject = XmlObject.Factory.parse(dom.getDocumentElement());
154 			serializePretty(xmlObject, writer);
155 		}
156 		catch (Exception e)
157 		{
158 			throw new IOException( e.toString() );
159 		}
160    }
161    
162    public static void serializePretty( XmlObject xmlObject, Writer writer ) throws IOException
163 	{
164 		XmlOptions options = new XmlOptions();
165 		options.setSavePrettyPrint();
166 		options.setSavePrettyPrintIndent( 3 );
167 		options.setSaveNoXmlDecl();
168 		options.setSaveAggressiveNamespaces();
169 		xmlObject.save(writer, options);
170 	}
171 
172    public static void serialize( Document dom, Writer writer )
173    throws IOException
174 	{
175    	serialize( dom.getDocumentElement(), writer );
176 	}
177    
178    public static void serialize( Element elm, Writer writer )
179    throws IOException
180 	{
181    	try
182 		{
183 			XmlObject xmlObject = XmlObject.Factory.parse(elm);
184 			xmlObject.save( writer );
185 		}
186 		catch (XmlException e)
187 		{
188 			throw new IOException( e.toString() );
189 		}
190 	}
191    
192    static public void setElementText( Element elm, String text )
193    {
194       Node node = elm.getFirstChild();
195       if( node == null  )
196       {
197       	if( text != null)
198       		elm.appendChild( elm.getOwnerDocument().createTextNode( text ) );
199       }
200       else if( node.getNodeType() == Node.TEXT_NODE )
201       {
202          if( text == null )
203             node.getParentNode().removeChild( node );
204          else
205             node.setNodeValue( text );
206       }
207       else if( text != null )
208       {
209          Text textNode = node.getOwnerDocument().createTextNode( text );
210          elm.insertBefore( textNode, elm.getFirstChild() );
211       }
212    }
213 
214    public static String getChildElementText( Element elm, String name )
215    {
216       Element child = getFirstChildElement( elm, name );
217       return child == null ? null : getElementText( child );
218    }
219 
220    public static Element getFirstChildElement( Element elm )
221    {
222    	return getFirstChildElement( elm, null );
223    }
224    
225    public static Element getFirstChildElement( Element elm, String name )
226    {
227    	if( elm == null )
228    		return null;
229    	
230       NodeList nl = elm.getChildNodes();
231       for( int c = 0; c < nl.getLength(); c++ )
232       {
233          Node node = nl.item( c );
234          if( node.getNodeType() == Node.ELEMENT_NODE && (name == null || node.getNodeName().equals( name )) )
235             return (Element) node;
236       }
237 
238       return null;
239    }
240    
241    public static Element getFirstChildElementNS( Element elm, String tns, String localName )
242    {
243    	if( tns == null && localName == null )
244    		return getFirstChildElement( elm );
245    	
246    	if( tns == null )
247    		return getFirstChildElement( elm, localName );
248    	
249       NodeList nl = elm.getChildNodes();
250       for( int c = 0; c < nl.getLength(); c++ )
251       {
252          Node node = nl.item( c );
253          if( node.getNodeType() != Node.ELEMENT_NODE ) continue;
254          
255          if( localName == null && tns.equals( node.getNamespaceURI() ))
256          	return ( Element ) node;
257          
258          if( localName != null && tns.equals( node.getNamespaceURI() ) && localName.equals( node.getLocalName() ))
259          	return ( Element ) node;
260       }
261 
262       return null;
263    }
264 
265    static public String getElementText( Element elm )
266    {
267       Node node = elm.getFirstChild();
268       if( node != null && node.getNodeType() == Node.TEXT_NODE )
269          return node.getNodeValue();
270 
271       return null;
272    }
273    
274    static public String getFragmentText( DocumentFragment elm )
275    {
276       Node node = elm.getFirstChild();
277       if( node != null && node.getNodeType() == Node.TEXT_NODE )
278          return node.getNodeValue();
279 
280       return null;
281    }
282 
283    public static String getChildElementText( Element elm, String name, String defaultValue )
284    {
285       String result = getChildElementText( elm, name );
286       return result == null ? defaultValue : result;
287    }
288 
289    static public String getNodeValue( Node node )
290    {
291    	if( node.getNodeType() == Node.ELEMENT_NODE )
292    		return getElementText( (Element) node );
293    	else if( node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE )
294    		return getFragmentText( (DocumentFragment) node );
295    	else 
296    		return node.getNodeValue();
297    }
298 
299    public static Node createNodeFromPath( Element modelElement, String path )
300    {
301       Document document = modelElement.getOwnerDocument();
302       StringTokenizer st = new StringTokenizer( path, "/" );
303       while( st.hasMoreTokens() )
304       {
305          String t = st.nextToken();
306 
307          if( st.hasMoreTokens() )
308          {
309             if( t.equals( ".." ) )
310             {
311                modelElement = (Element) modelElement.getParentNode();
312             }
313             else
314             {
315                Element elm = getFirstChildElement( modelElement, t );
316                if( elm == null )
317                   modelElement = (Element) modelElement.insertBefore(
318                      document.createElement( t ),
319                      getFirstChildElement( modelElement, t ) );
320                else
321                   modelElement = elm;
322             }
323          }
324          else
325          {
326             modelElement = (Element) modelElement.insertBefore(
327                document.createElement( t ),
328                getFirstChildElement( modelElement, t ) );
329          }
330       }
331 
332       return modelElement;
333    }
334 
335    public static Element addChildElement( Element element, String name, String text )
336    {
337       Document document = element.getOwnerDocument();
338       Element result = (Element) element.appendChild( document.createElement( name ) );
339       if( text != null )
340          result.appendChild( document.createTextNode( text ) );
341 
342       return result;
343    }
344 
345    public static void setChildElementText( Element element, String name, String text )
346    {
347       Element elm = getFirstChildElement( element, name );
348       if( elm == null )
349       {
350          elm = element.getOwnerDocument().createElement( name );
351          element.appendChild( elm );
352       }
353 
354       setElementText( elm, text );
355    }
356 
357    public static Document parseXml( String xmlString ) throws IOException
358    {
359       return parse( new InputSource( new StringReader( xmlString )));
360    }
361    
362    public static void dumpParserErrors(XmlObject xmlObject)
363    {
364       List errors = new ArrayList();
365       xmlObject.validate(new XmlOptions().setErrorListener(errors));
366       for (Iterator i = errors.iterator(); i.hasNext();)
367       {
368          System.out.println(i.next());
369       }
370    }
371 
372 	public static String transferValues(String source, String dest)
373 	{
374 		if( StringUtils.isNullOrEmpty( source ) || StringUtils.isNullOrEmpty( dest ))
375 			return dest;
376 
377 		XmlCursor cursor = null;
378 		try
379 		{
380 			XmlObject sourceXml = XmlObject.Factory.parse( source );
381 			XmlObject destXml = XmlObject.Factory.parse( dest );
382 			
383 			cursor = sourceXml.newCursor();
384 			cursor.toNextToken();
385 			while( !cursor.isEnddoc() )
386 			{
387 				while( !cursor.isContainer() && !cursor.isEnddoc() )
388 					cursor.toNextToken();
389 				
390 				if( cursor.isContainer() )
391 				{
392 					Element elm = ( Element ) cursor.getDomNode();
393 					String path = createXPath( elm );
394 					XmlObject[] paths = destXml.selectPath( path );
395 					if( paths != null && paths.length > 0 )
396 					{
397 						Element elm2 = ( Element ) paths[0].getDomNode();
398 						
399 						// transfer attributes
400 						NamedNodeMap attributes = elm.getAttributes();
401 						for( int c = 0; c < attributes.getLength(); c++ )
402 						{
403 							Attr attr = (Attr) attributes.item( c );
404 							elm2.setAttribute( attr.getNodeName(), attr.getNodeValue() );
405 						}
406 						
407 						// transfer text
408 						setElementText( elm2, getElementText( elm ));
409 					}
410 					
411 					cursor.toNextToken();
412 				}
413 			}
414 
415 			return destXml.xmlText();
416 		}
417 		catch (Exception e)
418 		{
419 			SoapUI.logError( e );
420 		}
421 		finally
422 		{
423 			if( cursor != null )
424 				cursor.dispose();
425 		}
426 		
427 		return dest;
428 	}
429 
430 	/***
431 	 * Returns absolute xpath for specified element, ignores namespaces
432 	 *  
433 	 * @param elm the element to create for
434 	 * @return the elements path in its containing document
435 	 */
436 	
437 	public static String getElementPath(Element element)
438 	{
439 		Node elm = element;
440 		
441 		String result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]";
442 		while( elm.getParentNode() != null && elm.getParentNode().getNodeType() != Node.DOCUMENT_NODE )
443 		{
444 			elm = elm.getParentNode();
445 			result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]/" + result;
446 		}
447 
448 		return "/" + result;
449 	}
450 
451 	/***
452 	 * Gets the index of the specified element amongst elements with the same name
453 	 * 
454 	 * @param element the element to get for
455 	 * @return the index of the element, will be >= 1
456 	 */
457 	
458 	public static int getElementIndex(Node element)
459 	{
460 		int result = 1;
461 		
462 		Node elm = element.getPreviousSibling();
463 		while( elm != null )
464 		{
465 			if( elm.getNodeType() == Node.ELEMENT_NODE && elm.getNodeName().equals( element.getNodeName() ))
466 				result++;
467 			elm = elm.getPreviousSibling();
468 		}
469 		
470 		return result;	
471 	}
472 	
473 	public static String declareXPathNamespaces( String xmlString ) throws XmlException
474 	{
475 		return declareXPathNamespaces( XmlObject.Factory.parse(xmlString));
476 	}
477 	
478 	public static synchronized String prettyPrintXml( String xml )
479 	{
480       try
481       {
482       	if( StringUtils.isNullOrEmpty( xml ))
483       		return xml;
484       	
485          StringWriter writer = new StringWriter();
486          XmlUtils.serializePretty( XmlObject.Factory.parse( xml ), writer );
487          return writer.toString();
488       }
489       catch( Exception e )
490       {
491       	log.warn( "Failed to prettyPrint xml [" + xml + "]: " + e );
492          return xml;
493       }
494 	}
495 	
496 	public static synchronized String prettyPrintXml( XmlObject xml )
497 	{
498       try
499       {
500       	if( xml == null )
501       		return null;
502       	
503          StringWriter writer = new StringWriter();
504          XmlUtils.serializePretty( xml, writer );
505          return writer.toString();
506       }
507       catch( Exception e )
508       {
509       	log.warn( "Failed to prettyPrint xml [" + xml + "]: " + e );
510          return xml.xmlText();
511       }
512 	}
513 
514 	public static String declareXPathNamespaces(WsdlInterface iface)
515 	{
516 		StringBuffer buf = new StringBuffer();
517 		buf.append( "declare namespace soap='" );
518 		buf.append( iface.getSoapVersion().getEnvelopeNamespace() );
519 		buf.append( "';\n");
520 		
521 		try
522 		{
523 			Collection<String> namespaces = iface.getWsdlContext().getDefinedNamespaces();
524 			int c = 1;
525 			for (Iterator<String> i = namespaces.iterator(); i.hasNext();)
526 			{
527 				buf.append("declare namespace ns");
528 				buf.append(c++);
529 				buf.append("='");
530 				buf.append(i.next());
531 				buf.append("';\n");
532 			}
533 		}
534 		catch (Exception e)
535 		{
536 			SoapUI.logError( e );
537 		}		
538 		
539 		return buf.toString();
540 	}
541 	
542 	public static String createXPath(Node node )
543 	{
544 	   return createXPath( node, false, false, false, null );
545 	}
546 	
547 	public static String createAbsoluteXPath(Node node )
548    {
549       return createXPath( node, false, false, true, null );
550    }
551   
552 	public static String createXPath(Node node, boolean anonymous, boolean selectText, XPathModifier modifier )
553 	{
554       return createXPath( node, anonymous, selectText, false, modifier );
555    }
556    
557 	public static String createXPath(Node node, boolean anonymous, boolean selectText, boolean absolute, XPathModifier modifier )
558    {
559       XPathData xpathData = createXPathData( node, anonymous, selectText, absolute );
560       if(xpathData == null)
561          return null;
562       return xpathData.buildXPath(modifier);
563    }
564 
565    public static XPathData createXPathData(Node node, boolean anonymous, boolean selectText, boolean absolute )
566    {
567       StringToStringMap nsMap = new StringToStringMap();
568       List<String> pathComponents = new ArrayList<String>();
569       
570       int nsCnt = 1;
571 		
572 		String namespaceURI = node.getNamespaceURI();
573 //		if( node.getNodeType() == Node.TEXT_NODE )
574 //		{
575 //			node = node.getParentNode();
576 //		}
577 		if( node.getNodeType() == Node.ATTRIBUTE_NODE )
578 		{
579 			if( namespaceURI.length() > 0 )
580 			{
581 				String prefix = node.getPrefix();
582 				if( prefix == null || prefix.length() == 0 )
583 					prefix = "ns" + nsCnt++;
584 				
585             nsMap.put( namespaceURI, prefix );
586             pathComponents.add( "@" + prefix + ":" + node.getLocalName() );
587 			}
588 			else
589 			{
590             pathComponents.add( "@" + node.getLocalName() );
591 			}
592 			node = ((Attr)node).getOwnerElement();
593 		}
594 		else if( node.getNodeType() == Node.DOCUMENT_NODE )
595 		{
596 			node = ((Document)node).getDocumentElement();
597 		}
598 //		else if( node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE )
599 //		{
600 //			node = ((DocumentFragment)node).getOwnerDocument().getDocumentElement();
601 //		}
602 		
603 		if( node.getNodeType() == Node.ELEMENT_NODE )  
604 		{
605 			int index = anonymous ? 0 : findNodeIndex( node );
606 			
607 			String pc = null;
608 		
609 			namespaceURI = node.getNamespaceURI();
610 			if( namespaceURI != null && namespaceURI.length() > 0 )
611 			{
612 				String prefix = node.getPrefix();
613 				if( prefix == null || prefix.length() == 0 )
614 					prefix = "ns" + nsCnt++;
615 				
616             nsMap.put( namespaceURI, prefix );
617 				pc = prefix + ":" + node.getLocalName();
618 			}
619 			else
620 			{
621 				pc = node.getLocalName();
622 			}
623 			
624 			String elementText = XmlUtils.getElementText( (Element) node );
625 			
626 			// not an attribute?
627 			if( selectText && pathComponents.isEmpty() && elementText != null && elementText.trim().length() > 0  )
628             pathComponents.add( "text()" );
629 			
630          pathComponents.add( pc + ((index == 0 ) ? "" : "[" + index + "]" ));
631 		}
632 		else
633 			return null;
634 		
635 		node = node.getParentNode();
636 		namespaceURI = node.getNamespaceURI();
637 		while( node != null && node.getNodeType() == Node.ELEMENT_NODE && 
638 		      (absolute ||
639 		       (!"Body".equals(node.getNodeName()) && 
640 				  !SoapVersion.Soap11.getEnvelopeNamespace().equals(namespaceURI) &&
641 				  !SoapVersion.Soap12.getEnvelopeNamespace().equals(namespaceURI) ) ) )
642 		{
643 			int index = anonymous ? 0 : findNodeIndex( node );
644 			
645 			String ns = nsMap.get( namespaceURI );
646 			String pc = null;
647 			
648 			if( ns == null && namespaceURI != null && namespaceURI.length() > 0 )
649 			{
650 				String prefix = node.getPrefix();
651 				if( prefix == null || prefix.length() == 0 )
652 					prefix = "ns" + nsCnt++;
653 				
654             nsMap.put( namespaceURI, prefix );
655 				ns = nsMap.get( namespaceURI );
656 				
657 				pc = prefix + ":" + node.getLocalName();
658 			}
659 			else if( ns != null ) 
660 			{
661 				 pc = ns + ":" + node.getLocalName();
662 			}
663 			else
664 			{
665 				 pc = node.getLocalName();
666 			}
667 			
668          pathComponents.add( pc + ((index == 0 ) ? "" : "[" + index + "]" ));
669 			node = node.getParentNode();
670 			namespaceURI = node.getNamespaceURI();
671 		}
672 		
673       return new XPathData(nsMap, pathComponents, absolute);
674 	}
675 
676 	private static int findNodeIndex(Node node)
677 	{
678 		String nm = node.getLocalName();
679 		String ns = node.getNamespaceURI();
680 		short nt = node.getNodeType();
681 		
682 		Node parentNode = node.getParentNode();
683 		if( parentNode.getNodeType() != Node.ELEMENT_NODE )
684 			return 1;
685 		
686 		Node child = parentNode.getFirstChild();
687 		
688 		int ix = 0;
689 		while( child != null )
690 		{
691 			if( child == node )
692 				return ix+1;
693 			
694 			if( child.getNodeType() == nt && 
695 				 nm.equals( child.getLocalName() ) && ns.equals( child.getNamespaceURI()))
696 				ix++; 
697 			
698 			child = child.getNextSibling();
699 		}
700 
701 		throw new RuntimeException( "Child node not found in parent!?" );
702 	}
703 
704 	public static boolean setNodeValue( Node domNode, String string )
705 	{
706 		short nodeType = domNode.getNodeType();
707 		if( nodeType == Node.ELEMENT_NODE )
708 		{
709 			setElementText( ( Element ) domNode, string );
710 			return true;
711 		}
712 		else if( nodeType == Node.ATTRIBUTE_NODE || nodeType == Node.TEXT_NODE )
713 		{
714 			domNode.setNodeValue( string );
715 			return true;
716 		}
717 		
718 		return false;
719 	}
720 
721 	public static String declareXPathNamespaces( XmlObject xmlObject )
722 	{
723 		Map<QName,String> map = new HashMap<QName,String>();
724 		XmlCursor cursor = xmlObject.newCursor();
725 		
726 		while( cursor.hasNextToken() )
727 		{
728 			if( cursor.toNextToken().isNamespace() )
729 				map.put( cursor.getName(), cursor.getTextValue() );
730 		}
731 		
732 		Iterator<QName> i = map.keySet().iterator();
733 		int nsCnt = 0;
734 		
735 		StringBuffer buf = new StringBuffer();
736 		Set<String> prefixes = new HashSet<String>();
737 		Set<String> usedPrefixes = new HashSet<String>();
738 		
739 		while( i.hasNext() )
740 		{
741 			QName name = i.next();
742 			String prefix = name.getLocalPart();
743 			if( prefix.length() == 0 ) prefix = "ns" + Integer.toString( ++nsCnt );
744 			else if( prefix.equals( "xsd") || prefix.equals( "xsi")) continue;
745 			
746 			if( usedPrefixes.contains( prefix ))
747 			{
748 				int c = 1;
749 				while( usedPrefixes.contains( prefix + c )) c++;
750 				
751 				prefix = prefix + Integer.toString( c );
752 			}
753 			else prefixes.add( prefix );
754 			
755 			buf.append( "declare namespace " );
756 			buf.append( prefix );
757 			buf.append( "='" );
758 			buf.append( map.get( name ));
759 			buf.append( "';\n");
760 			
761 			usedPrefixes.add( prefix );
762 		}
763 		
764 		return buf.toString();
765 	}
766 
767 	public static String setXPathContent( String emptyResponse, String string, String actor )
768 	{
769 		try
770 		{
771 			XmlObject xmlObject = XmlObject.Factory.parse( emptyResponse );
772 			
773 			String namespaces = declareXPathNamespaces( xmlObject );
774 			if( namespaces != null && namespaces.trim().length() > 0 )
775 				string = namespaces + string;
776 			
777 			XmlObject[] path = xmlObject.selectPath( string );
778 			for( XmlObject xml : path )
779 			{
780 				setNodeValue( xml.getDomNode(), actor );
781 			}
782 			
783 			return xmlObject.toString();
784 		}
785 		catch( Exception e )
786 		{
787 			SoapUI.logError( e );
788 		}
789 		
790 		return emptyResponse;
791 	}
792 	
793 	public static QName getQName( Node node )
794 	{
795 		if( node.getNamespaceURI() == null )
796 			return new QName( node.getNodeName());
797 		else
798 			return new QName( node.getNamespaceURI(), node.getLocalName() );
799 	}
800 
801 	public static String removeXPathNamespaceDeclarations( String xpath )
802 	{
803 		while( xpath.startsWith( "declare namespace" ))
804 		{
805 			int ix = xpath.indexOf( ';' );
806 			if( ix == -1 )
807 				break;
808 			
809 			xpath = xpath.substring( ix+1 ).trim();
810 		}
811 		return xpath;
812 	}
813 
814 	public static String stripWhitespaces( String content )
815 	{
816 		try
817 		{
818 			XmlObject xml = XmlObject.Factory.parse( content, new XmlOptions().setLoadStripWhitespace().setLoadStripComments() );
819 			content = xml.xmlText();
820 		}
821 		catch( Exception e )
822 		{
823 			SoapUI.logError( e );
824 		}
825 		
826 		return content;
827 	}
828 
829 	public static NodeList getChildElements( Element elm )
830 	{
831 		List<Element> list = new ArrayList<Element>();
832 		
833 		NodeList nl = elm.getChildNodes();
834 		for( int c = 0; c < nl.getLength(); c++ )
835 		{
836 			Node item = nl.item( c );
837 			if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE )
838 				list.add(  ( Element ) item );
839 		}
840 		
841 		return new ElementNodeList( list );
842 	}
843 	
844 	public static NodeList getChildElementsByTagName( Element elm, String name )
845 	{
846 		List<Element> list = new ArrayList<Element>();
847 		
848 		NodeList nl = elm.getChildNodes();
849 		for( int c = 0; c < nl.getLength(); c++ )
850 		{
851 			Node item = nl.item( c );
852 			if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE && name.equals( item.getNodeName()) )
853 				list.add(  ( Element ) item );
854 		}
855 		
856 		return new ElementNodeList( list );
857 	}
858 	
859 	public static NodeList getChildElementsByTagNameNS( Element elm, String namespaceUri, String localName )
860 	{
861 		List<Element> list = new ArrayList<Element>();
862 		
863 		NodeList nl = elm.getChildNodes();
864 		for( int c = 0; c < nl.getLength(); c++ )
865 		{
866 			Node item = nl.item( c );
867 			if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE && 
868 						localName.equals( item.getLocalName())	&& namespaceUri.equals( item.getNamespaceURI()))
869 				list.add(  ( Element ) item );
870 		}
871 		
872 		return new ElementNodeList( list );
873 	}
874 
875 	private final static class ElementNodeList implements NodeList
876 	{
877 		private final List<Element> list;
878 
879 		public ElementNodeList( List<Element> list )
880 		{
881 			this.list = list;
882 		}
883 
884 		public int getLength()
885 		{
886 			return list.size();
887 		}
888 
889 		public Node item( int index )
890 		{
891 			return list.get( index );
892 		}
893    }
894 
895 	public static boolean seemsToBeXml( String str )
896 	{
897 		try
898 		{
899 			if( StringUtils.isNullOrEmpty( str ))
900       		return false;
901 			
902 			return XmlObject.Factory.parse( str ) != null;
903 		}
904 		catch( Exception e )
905 		{
906 			return false;
907 		}
908 	}
909 
910 	public static String extractNamespaces( String xpath )
911 	{
912 		String result = xpath;
913 		int ix = xpath.lastIndexOf( "declare namespace" );
914 		if( ix != -1 )
915 		{
916 			ix = xpath.indexOf( '\'', ix+1 );
917 			if( ix != -1 )
918 			{
919 				ix = xpath.indexOf( '\'', ix+1 );
920 				if( ix != -1 )
921 				{
922 					ix = xpath.indexOf( ';' );
923 					if( ix != -1 )
924 					{
925 						result = xpath.substring( 0, ix+1 );
926 					}
927 				}
928 			}
929 		}
930 		
931 		return result;
932 	}
933 
934 	public static String removeUnneccessaryNamespaces( String xml )
935 	{
936 		if( StringUtils.isNullOrEmpty( xml ))
937 			return xml;
938 		
939 		XmlObject xmlObject = null;
940 		XmlCursor cursor = null;
941 		try
942 		{
943 			xmlObject = XmlObject.Factory.parse( xml );
944 	
945 			cursor = xmlObject.newCursor();
946 			while( cursor.currentTokenType() != TokenType.START && cursor.currentTokenType() != TokenType.ENDDOC )
947 			{
948 				cursor.toNextToken();
949 			}
950 			
951 			if( cursor.currentTokenType() == TokenType.START )
952 			{
953 				Map nsMap = new HashMap();
954 		
955 				cursor.getAllNamespaces( nsMap );
956 				nsMap.remove( cursor.getDomNode().getPrefix() );
957 		
958 				NamedNodeMap attributes = cursor.getDomNode().getAttributes();
959 				for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
960 				{
961 					nsMap.remove( attributes.item( c ).getPrefix() );
962 				}
963 		
964 				if( cursor.toFirstChild() )
965 				{
966 					while( cursor.getDomNode() != xmlObject.getDomNode() )
967 					{
968 						attributes = cursor.getDomNode().getAttributes();
969 						for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
970 						{
971 							nsMap.remove( attributes.item( c ).getPrefix() );
972 						}
973 		
974 						nsMap.remove( cursor.getDomNode().getPrefix() );
975 						cursor.toNextToken();
976 					}
977 				}
978 		
979 				xml = xmlObject.xmlText( new XmlOptions().setSaveOuter().setSavePrettyPrint()
980 							.setSaveImplicitNamespaces( nsMap ) );
981 			}
982 		}
983 		catch( XmlException e )
984 		{
985 			
986 		}
987 		finally
988 		{
989 			if( cursor != null )
990 				cursor.dispose();
991 		}
992 		
993 		return xml;
994 	}
995 
996 	public static String replaceNameInPathOrQuery( String pathOrQuery, String oldName, String newName ) throws Exception
997 	   {
998 	   	Tokenizer t = new Tokenizer();
999 	   	t.tokenize(pathOrQuery, 0, -1, 1);
1000 	   	StringBuffer result = new StringBuffer();
1001 	   	int lastIx = 0;
1002 	   	
1003 	   	while( t.currentToken != Token.EOF )
1004 	   	{
1005 	   		if( t.currentToken == Token.NAME && t.currentTokenValue.equals( oldName ))
1006 	   		{
1007 	   			result.append( pathOrQuery.substring( lastIx, t.currentTokenStartOffset ) );
1008 	   			result.append( newName );
1009 	   			lastIx = t.currentTokenStartOffset + t.currentTokenValue.length();
1010 	   		}
1011 	   		
1012 	   		t.next();
1013 	   	}
1014 	
1015 	   	if( lastIx < pathOrQuery.length())
1016 	   		result.append( pathOrQuery.substring( lastIx ) );
1017 	//   	
1018 	   	System.out.println( "returning " + result.toString() );
1019 	   	return result.toString();
1020 	   }
1021 }
1022