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