View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 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.PrintWriter;
18  import java.io.StringReader;
19  import java.io.StringWriter;
20  import java.io.Writer;
21  import java.sql.ResultSet;
22  import java.sql.ResultSetMetaData;
23  import java.sql.SQLException;
24  import java.sql.Statement;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.HashMap;
28  import java.util.HashSet;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  import java.util.StringTokenizer;
34  
35  import javax.xml.namespace.QName;
36  import javax.xml.parsers.DocumentBuilder;
37  import javax.xml.parsers.DocumentBuilderFactory;
38  import javax.xml.parsers.ParserConfigurationException;
39  
40  import net.sf.saxon.expr.Token;
41  import net.sf.saxon.expr.Tokenizer;
42  
43  import org.apache.log4j.Logger;
44  import org.apache.xml.serialize.OutputFormat;
45  import org.apache.xml.serialize.XMLSerializer;
46  import org.apache.xmlbeans.SchemaType;
47  import org.apache.xmlbeans.XmlAnySimpleType;
48  import org.apache.xmlbeans.XmlCursor;
49  import org.apache.xmlbeans.XmlCursor.TokenType;
50  import org.apache.xmlbeans.XmlException;
51  import org.apache.xmlbeans.XmlObject;
52  import org.apache.xmlbeans.XmlOptions;
53  import org.w3c.dom.Attr;
54  import org.w3c.dom.CDATASection;
55  import org.w3c.dom.Document;
56  import org.w3c.dom.DocumentFragment;
57  import org.w3c.dom.Element;
58  import org.w3c.dom.NamedNodeMap;
59  import org.w3c.dom.Node;
60  import org.w3c.dom.NodeList;
61  import org.w3c.dom.ProcessingInstruction;
62  import org.w3c.dom.Text;
63  import org.xml.sax.InputSource;
64  import org.xml.sax.SAXException;
65  
66  import com.eviware.soapui.SoapUI;
67  import com.eviware.soapui.impl.wsdl.WsdlInterface;
68  import com.eviware.soapui.impl.wsdl.support.Constants;
69  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
70  import com.eviware.soapui.support.StringUtils;
71  import com.eviware.soapui.support.types.StringToStringMap;
72  
73  /***
74   * General XML-related utilities
75   */
76  
77  @SuppressWarnings( "deprecation" )
78  public final class XmlUtils
79  {
80  	private static DocumentBuilder documentBuilder;
81  	private final static Logger log = Logger.getLogger( XmlUtils.class );
82  
83  	static synchronized public Document parse( InputStream in )
84  	{
85  		try
86  		{
87  			return ensureDocumentBuilder().parse( in );
88  		}
89  		catch( Exception e )
90  		{
91  			log.error( "Error parsing InputStream; " + e.getMessage(), e );
92  		}
93  
94  		return null;
95  	}
96  
97  	static synchronized public Document parse( String fileName ) throws IOException
98  	{
99  		try
100 		{
101 			return ensureDocumentBuilder().parse( fileName );
102 		}
103 		catch( SAXException e )
104 		{
105 			log.error( "Error parsing fileName [" + fileName + "]; " + e.getMessage(), e );
106 		}
107 
108 		return null;
109 	}
110 
111 	public static String entitize( String xml )
112 	{
113 		return xml.replaceAll( "&", "&amp;" ).replaceAll( "<", "&lt;" ).replaceAll( ">", "&gt;" )
114 				.replaceAll( "\"", "&quot;" ).replaceAll( "'", "&apos;" );
115 	}
116 
117 	public static String entitizeContent( String xml )
118 	{
119 		return xml.replaceAll( "&", "&amp;" ).replaceAll( "\"", "&quot;" ).replaceAll( "'", "&apos;" );
120 	}
121 
122 	static synchronized public Document parse( InputSource inputSource ) throws IOException
123 	{
124 		try
125 		{
126 			return ensureDocumentBuilder().parse( inputSource );
127 		}
128 		catch( SAXException e )
129 		{
130 			throw new IOException( e.toString() );
131 		}
132 	}
133 
134 	private static DocumentBuilder ensureDocumentBuilder()
135 	{
136 		if( documentBuilder == null )
137 		{
138 			try
139 			{
140 				DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
141 				dbf.setNamespaceAware( true );
142 				documentBuilder = dbf.newDocumentBuilder();
143 			}
144 			catch( ParserConfigurationException e )
145 			{
146 				log.error( "Error creating DocumentBuilder; " + e.getMessage() );
147 			}
148 		}
149 
150 		return documentBuilder;
151 	}
152 
153 	public static String serializePretty( Document document )
154 	{
155 		try
156 		{
157 			Writer out = new StringWriter();
158 			serializePretty( document, out );
159 			return out.toString();
160 		}
161 		catch( IOException e )
162 		{
163 			log.error( "Failed to seraialize: " + e );
164 		}
165 		return null;
166 	}
167 
168 	public static void serializePretty( Document dom, Writer writer ) throws IOException
169 	{
170 		try
171 		{
172 			XmlObject xmlObject = XmlObject.Factory.parse( dom.getDocumentElement() );
173 			serializePretty( xmlObject, writer );
174 		}
175 		catch( Exception e )
176 		{
177 			throw new IOException( e.toString() );
178 		}
179 	}
180 
181 	public static void serializePretty( XmlObject xmlObject, Writer writer ) throws IOException
182 	{
183 		XmlOptions options = new XmlOptions();
184 		options.setSavePrettyPrint();
185 		options.setSavePrettyPrintIndent( 3 );
186 		options.setSaveNoXmlDecl();
187 		options.setSaveAggressiveNamespaces();
188 		// StringToStringMap map = new StringToStringMap();
189 		// map.put( SoapVersion.Soap11.getEnvelopeNamespace(), "SOAPENV" );
190 		// map.put( SoapVersion.Soap12.getEnvelopeNamespace(), "SOAPENV" );
191 		//
192 		// options.setSaveSuggestedPrefixes( map );
193 
194 		xmlObject.save( writer, options );
195 	}
196 
197 	public static void serialize( Document dom, Writer writer ) throws IOException
198 	{
199 		serialize( dom.getDocumentElement(), writer );
200 	}
201 
202 	public static void serialize( Element elm, Writer writer ) throws IOException
203 	{
204 		try
205 		{
206 			XmlObject xmlObject = XmlObject.Factory.parse( elm );
207 			xmlObject.save( writer );
208 		}
209 		catch( XmlException e )
210 		{
211 			throw new IOException( e.toString() );
212 		}
213 	}
214 
215 	static public String serialize( Node node, boolean prettyPrint )
216 	{
217 		try
218 		{
219 			XmlObject xmlObject = XmlObject.Factory.parse( node );
220 			return prettyPrint ? xmlObject.xmlText( new XmlOptions().setSavePrettyPrint() ) : xmlObject.xmlText();
221 		}
222 		catch( XmlException e )
223 		{
224 			return e.toString();
225 		}
226 	}
227 
228 	static public void setElementText( Element elm, String text )
229 	{
230 		Node node = elm.getFirstChild();
231 		if( node == null )
232 		{
233 			if( text != null )
234 				elm.appendChild( elm.getOwnerDocument().createTextNode( text ) );
235 		}
236 		else if( node.getNodeType() == Node.TEXT_NODE )
237 		{
238 			if( text == null )
239 				node.getParentNode().removeChild( node );
240 			else
241 				node.setNodeValue( text );
242 		}
243 		else if( text != null )
244 		{
245 			Text textNode = node.getOwnerDocument().createTextNode( text );
246 			elm.insertBefore( textNode, elm.getFirstChild() );
247 		}
248 	}
249 
250 	public static String getChildElementText( Element elm, String name )
251 	{
252 		Element child = getFirstChildElement( elm, name );
253 		return child == null ? null : getElementText( child );
254 	}
255 
256 	public static Element getFirstChildElement( Element elm )
257 	{
258 		return getFirstChildElement( elm, null );
259 	}
260 
261 	public static Element getFirstChildElement( Element elm, String name )
262 	{
263 		if( elm == null )
264 			return null;
265 
266 		NodeList nl = elm.getChildNodes();
267 		for( int c = 0; c < nl.getLength(); c++ )
268 		{
269 			Node node = nl.item( c );
270 			if( node.getNodeType() == Node.ELEMENT_NODE && ( name == null || node.getNodeName().equals( name ) ) )
271 				return ( Element )node;
272 		}
273 
274 		return null;
275 	}
276 
277 	public static Element getFirstChildElementIgnoreCase( Element elm, String name )
278 	{
279 		if( elm == null )
280 			return null;
281 
282 		NodeList nl = elm.getChildNodes();
283 		for( int c = 0; c < nl.getLength(); c++ )
284 		{
285 			Node node = nl.item( c );
286 			if( node.getNodeType() == Node.ELEMENT_NODE && ( name == null || node.getNodeName().equalsIgnoreCase( name ) ) )
287 				return ( Element )node;
288 		}
289 
290 		return null;
291 	}
292 
293 	public static Element getFirstChildElementNS( Element elm, String tns, String localName )
294 	{
295 		if( tns == null && localName == null )
296 			return getFirstChildElement( elm );
297 
298 		if( tns == null )
299 			return getFirstChildElement( elm, localName );
300 
301 		NodeList nl = elm.getChildNodes();
302 		for( int c = 0; c < nl.getLength(); c++ )
303 		{
304 			Node node = nl.item( c );
305 			if( node.getNodeType() != Node.ELEMENT_NODE )
306 				continue;
307 
308 			if( localName == null && tns.equals( node.getNamespaceURI() ) )
309 				return ( Element )node;
310 
311 			if( localName != null && tns.equals( node.getNamespaceURI() ) && localName.equals( node.getLocalName() ) )
312 				return ( Element )node;
313 		}
314 
315 		return null;
316 	}
317 
318 	static public String getElementText( Element elm )
319 	{
320 		Node node = elm.getFirstChild();
321 		if( node != null && node.getNodeType() == Node.TEXT_NODE )
322 			return node.getNodeValue();
323 
324 		return null;
325 	}
326 
327 	static public String getFragmentText( DocumentFragment elm )
328 	{
329 		Node node = elm.getFirstChild();
330 		if( node != null && node.getNodeType() == Node.TEXT_NODE )
331 			return node.getNodeValue();
332 
333 		return null;
334 	}
335 
336 	public static String getChildElementText( Element elm, String name, String defaultValue )
337 	{
338 		String result = getChildElementText( elm, name );
339 		return result == null ? defaultValue : result;
340 	}
341 
342 	static public String getNodeValue( Node node )
343 	{
344 		if( node == null )
345 			return null;
346 
347 		if( node.getNodeType() == Node.ELEMENT_NODE )
348 			return getElementText( ( Element )node );
349 		else if( node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE )
350 			return getFragmentText( ( DocumentFragment )node );
351 		else
352 			return node.getNodeValue();
353 	}
354 
355 	public static Node createNodeFromPath( Element modelElement, String path )
356 	{
357 		Document document = modelElement.getOwnerDocument();
358 		StringTokenizer st = new StringTokenizer( path, "/" );
359 		while( st.hasMoreTokens() )
360 		{
361 			String t = st.nextToken();
362 
363 			if( st.hasMoreTokens() )
364 			{
365 				if( t.equals( ".." ) )
366 				{
367 					modelElement = ( Element )modelElement.getParentNode();
368 				}
369 				else
370 				{
371 					Element elm = getFirstChildElement( modelElement, t );
372 					if( elm == null )
373 						modelElement = ( Element )modelElement.insertBefore( document.createElement( t ),
374 								getFirstChildElement( modelElement, t ) );
375 					else
376 						modelElement = elm;
377 				}
378 			}
379 			else
380 			{
381 				modelElement = ( Element )modelElement.insertBefore( document.createElement( t ),
382 						getFirstChildElement( modelElement, t ) );
383 			}
384 		}
385 
386 		return modelElement;
387 	}
388 
389 	public static Element addChildElement( Element element, String name, String text )
390 	{
391 		Document document = element.getOwnerDocument();
392 		Element result = ( Element )element.appendChild( document.createElement( name ) );
393 		if( text != null )
394 			result.appendChild( document.createTextNode( text ) );
395 
396 		return result;
397 	}
398 
399 	public static void setChildElementText( Element element, String name, String text )
400 	{
401 		Element elm = getFirstChildElement( element, name );
402 		if( elm == null )
403 		{
404 			elm = element.getOwnerDocument().createElement( name );
405 			element.appendChild( elm );
406 		}
407 
408 		setElementText( elm, text );
409 	}
410 
411 	public static Document parseXml( String xmlString ) throws IOException
412 	{
413 		return parse( new InputSource( new StringReader( xmlString ) ) );
414 	}
415 
416 	public static void dumpParserErrors( XmlObject xmlObject )
417 	{
418 		List<?> errors = new ArrayList<Object>();
419 		xmlObject.validate( new XmlOptions().setErrorListener( errors ) );
420 		for( Iterator<?> i = errors.iterator(); i.hasNext(); )
421 		{
422 			System.out.println( i.next() );
423 		}
424 	}
425 
426 	public static String transferValues( String source, String dest )
427 	{
428 		if( StringUtils.isNullOrEmpty( source ) || StringUtils.isNullOrEmpty( dest ) )
429 			return dest;
430 
431 		XmlCursor cursor = null;
432 		try
433 		{
434 			XmlObject sourceXml = XmlObject.Factory.parse( source );
435 			XmlObject destXml = XmlObject.Factory.parse( dest );
436 
437 			cursor = sourceXml.newCursor();
438 			cursor.toNextToken();
439 			while( !cursor.isEnddoc() )
440 			{
441 				while( !cursor.isContainer() && !cursor.isEnddoc() )
442 					cursor.toNextToken();
443 
444 				if( cursor.isContainer() )
445 				{
446 					Element elm = ( Element )cursor.getDomNode();
447 					String path = createXPath( elm );
448 					XmlObject[] paths = destXml.selectPath( path );
449 					if( paths != null && paths.length > 0 )
450 					{
451 						Element elm2 = ( Element )paths[0].getDomNode();
452 
453 						// transfer attributes
454 						transferAttributes( elm, elm2 );
455 
456 						// transfer text
457 						setElementText( elm2, getElementText( elm ) );
458 
459 						while( elm.getNextSibling() != null && elm2.getNextSibling() != null
460 								&& elm.getNextSibling().getNodeName().equals( elm.getNodeName() )
461 								&& !elm2.getNextSibling().getNodeName().equals( elm2.getNodeName() ) )
462 						{
463 							elm2 = ( Element )elm2.getParentNode().insertBefore(
464 									elm2.getOwnerDocument().createElementNS( elm2.getNamespaceURI(), elm2.getLocalName() ),
465 									elm2.getNextSibling() );
466 
467 							elm = ( Element )elm.getNextSibling();
468 
469 							// transfer attributes
470 							transferAttributes( elm, elm2 );
471 
472 							// transfer text
473 							setElementText( elm2, getElementText( elm ) );
474 						}
475 
476 					}
477 
478 					cursor.toNextToken();
479 				}
480 			}
481 
482 			return destXml.xmlText();
483 		}
484 		catch( Exception e )
485 		{
486 			SoapUI.logError( e );
487 		}
488 		finally
489 		{
490 			if( cursor != null )
491 				cursor.dispose();
492 		}
493 
494 		return dest;
495 	}
496 
497 	private static void transferAttributes( Element elm, Element elm2 )
498 	{
499 		NamedNodeMap attributes = elm.getAttributes();
500 		for( int c = 0; c < attributes.getLength(); c++ )
501 		{
502 			Attr attr = ( Attr )attributes.item( c );
503 			elm2.setAttributeNodeNS( ( Attr )elm2.getOwnerDocument().importNode( attr, true ) );
504 		}
505 	}
506 
507 	/***
508 	 * Returns absolute xpath for specified element, ignores namespaces
509 	 * 
510 	 * @param element
511 	 *           the element to create for
512 	 * @return the elements path in its containing document
513 	 */
514 
515 	public static String getElementPath( Element element )
516 	{
517 		Node elm = element;
518 
519 		String result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]";
520 		while( elm.getParentNode() != null && elm.getParentNode().getNodeType() != Node.DOCUMENT_NODE )
521 		{
522 			elm = elm.getParentNode();
523 			result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]/" + result;
524 		}
525 
526 		return "/" + result;
527 	}
528 
529 	/***
530 	 * Gets the index of the specified element amongst elements with the same
531 	 * name
532 	 * 
533 	 * @param element
534 	 *           the element to get for
535 	 * @return the index of the element, will be >= 1
536 	 */
537 
538 	public static int getElementIndex( Node element )
539 	{
540 		int result = 1;
541 
542 		Node elm = element.getPreviousSibling();
543 		while( elm != null )
544 		{
545 			if( elm.getNodeType() == Node.ELEMENT_NODE && elm.getNodeName().equals( element.getNodeName() ) )
546 				result++ ;
547 			elm = elm.getPreviousSibling();
548 		}
549 
550 		return result;
551 	}
552 
553 	public static String declareXPathNamespaces( String xmlString ) throws XmlException
554 	{
555 		return declareXPathNamespaces( XmlObject.Factory.parse( xmlString ) );
556 	}
557 
558 	public static synchronized String prettyPrintXml( String xml )
559 	{
560 		try
561 		{
562 			if( !XmlUtils.seemsToBeXml( xml ) )
563 				return xml;
564 
565 			StringWriter writer = new StringWriter();
566 			XmlUtils.serializePretty( XmlObject.Factory.parse( xml ), writer );
567 			return writer.toString();
568 		}
569 		catch( Exception e )
570 		{
571 			log.warn( "Failed to prettyPrint xml [" + xml + "]: " + e );
572 			return xml;
573 		}
574 	}
575 
576 	public static synchronized String prettyPrintXml( XmlObject xml )
577 	{
578 		try
579 		{
580 			if( xml == null )
581 				return null;
582 
583 			StringWriter writer = new StringWriter();
584 			XmlUtils.serializePretty( xml, writer );
585 			return writer.toString();
586 		}
587 		catch( Exception e )
588 		{
589 			log.warn( "Failed to prettyPrint xml [" + xml + "]: " + e );
590 			return xml.xmlText();
591 		}
592 	}
593 
594 	public static String declareXPathNamespaces( WsdlInterface iface )
595 	{
596 		StringBuffer buf = new StringBuffer();
597 		buf.append( "declare namespace soap='" );
598 		buf.append( iface.getSoapVersion().getEnvelopeNamespace() );
599 		buf.append( "';\n" );
600 
601 		try
602 		{
603 			Collection<String> namespaces = iface.getWsdlContext().getInterfaceDefinition().getDefinedNamespaces();
604 			int c = 1;
605 			for( Iterator<String> i = namespaces.iterator(); i.hasNext(); )
606 			{
607 				buf.append( "declare namespace ns" );
608 				buf.append( c++ );
609 				buf.append( "='" );
610 				buf.append( i.next() );
611 				buf.append( "';\n" );
612 			}
613 		}
614 		catch( Exception e )
615 		{
616 			SoapUI.logError( e );
617 		}
618 
619 		return buf.toString();
620 	}
621 
622 	public static String createXPath( Node node )
623 	{
624 		return createXPath( node, false, false, false, null );
625 	}
626 
627 	public static String createAbsoluteXPath( Node node )
628 	{
629 		return createXPath( node, false, false, true, null );
630 	}
631 
632 	public static String createXPath( Node node, boolean anonymous, boolean selectText, XPathModifier modifier )
633 	{
634 		return createXPath( node, anonymous, selectText, false, modifier );
635 	}
636 
637 	public static String createXPath( Node node, boolean anonymous, boolean selectText, boolean absolute,
638 			XPathModifier modifier )
639 	{
640 		XPathData xpathData = createXPathData( node, anonymous, selectText, absolute );
641 		if( xpathData == null )
642 			return null;
643 		return xpathData.buildXPath( modifier );
644 	}
645 
646 	public static XPathData createXPathData( Node node, boolean anonymous, boolean selectText, boolean absolute )
647 	{
648 		StringToStringMap nsMap = new StringToStringMap();
649 		List<String> pathComponents = new ArrayList<String>();
650 
651 		int nsCnt = 1;
652 
653 		String namespaceURI = node.getNamespaceURI();
654 		// if( node.getNodeType() == Node.TEXT_NODE )
655 		// {
656 		// node = node.getParentNode();
657 		// }
658 		if( node.getNodeType() == Node.ATTRIBUTE_NODE )
659 		{
660 			if( namespaceURI != null && namespaceURI.length() > 0 )
661 			{
662 				String prefix = node.getPrefix();
663 				if( prefix == null || prefix.length() == 0 )
664 					prefix = "ns" + nsCnt++ ;
665 
666 				nsMap.put( namespaceURI, prefix );
667 				pathComponents.add( "@" + prefix + ":" + node.getLocalName() );
668 			}
669 			else
670 			{
671 				pathComponents.add( "@" + node.getLocalName() );
672 			}
673 			node = ( ( Attr )node ).getOwnerElement();
674 		}
675 		else if( node.getNodeType() == Node.DOCUMENT_NODE )
676 		{
677 			node = ( ( Document )node ).getDocumentElement();
678 		}
679 		// else if( node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE )
680 		// {
681 		// node =
682 		// ((DocumentFragment)node).getOwnerDocument().getDocumentElement();
683 		// }
684 
685 		if( node.getNodeType() == Node.ELEMENT_NODE )
686 		{
687 			int index = anonymous ? 0 : findNodeIndex( node );
688 
689 			String pc = null;
690 
691 			namespaceURI = node.getNamespaceURI();
692 			if( namespaceURI != null && namespaceURI.length() > 0 )
693 			{
694 				String prefix = node.getPrefix();
695 				if( prefix == null || prefix.length() == 0 )
696 					prefix = "ns" + nsCnt++ ;
697 
698 				while( !nsMap.containsKey( namespaceURI ) && nsMap.containsValue( prefix ) )
699 				{
700 					prefix = "ns" + nsCnt++ ;
701 				}
702 
703 				nsMap.put( namespaceURI, prefix );
704 				pc = prefix + ":" + node.getLocalName();
705 			}
706 			else
707 			{
708 				pc = node.getLocalName();
709 			}
710 
711 			String elementText = XmlUtils.getElementText( ( Element )node );
712 
713 			// not an attribute?
714 			if( selectText && pathComponents.isEmpty() && elementText != null && elementText.trim().length() > 0 )
715 				pathComponents.add( "text()" );
716 
717 			pathComponents.add( pc + ( ( index == 0 ) ? "" : "[" + index + "]" ) );
718 		}
719 		else
720 			return null;
721 
722 		node = node.getParentNode();
723 		namespaceURI = node.getNamespaceURI();
724 		while( node != null
725 				&& node.getNodeType() == Node.ELEMENT_NODE
726 				&& ( absolute || ( !"Body".equals( node.getNodeName() )
727 						&& !SoapVersion.Soap11.getEnvelopeNamespace().equals( namespaceURI ) && !SoapVersion.Soap12
728 						.getEnvelopeNamespace().equals( namespaceURI ) ) ) )
729 		{
730 			int index = anonymous ? 0 : findNodeIndex( node );
731 
732 			String ns = nsMap.get( namespaceURI );
733 			String pc = null;
734 
735 			if( ns == null && namespaceURI != null && namespaceURI.length() > 0 )
736 			{
737 				String prefix = node.getPrefix();
738 				if( prefix == null || prefix.length() == 0 )
739 					prefix = "ns" + nsCnt++ ;
740 
741 				while( !nsMap.containsKey( namespaceURI ) && nsMap.containsValue( prefix ) )
742 				{
743 					prefix = "ns" + nsCnt++ ;
744 				}
745 
746 				nsMap.put( namespaceURI, prefix );
747 				ns = nsMap.get( namespaceURI );
748 
749 				pc = prefix + ":" + node.getLocalName();
750 			}
751 			else if( ns != null )
752 			{
753 				pc = ns + ":" + node.getLocalName();
754 			}
755 			else
756 			{
757 				pc = node.getLocalName();
758 			}
759 
760 			pathComponents.add( pc + ( ( index == 0 ) ? "" : "[" + index + "]" ) );
761 			node = node.getParentNode();
762 			namespaceURI = node.getNamespaceURI();
763 		}
764 
765 		return new XPathData( nsMap, pathComponents, absolute );
766 	}
767 
768 	private static int findNodeIndex( Node node )
769 	{
770 		String nm = node.getLocalName();
771 		String ns = node.getNamespaceURI();
772 		short nt = node.getNodeType();
773 
774 		Node parentNode = node.getParentNode();
775 		if( parentNode.getNodeType() != Node.ELEMENT_NODE )
776 			return 1;
777 
778 		Node child = parentNode.getFirstChild();
779 
780 		int ix = 0;
781 		while( child != null )
782 		{
783 			if( child == node )
784 				return ix + 1;
785 
786 			if( child.getNodeType() == nt
787 					&& nm.equals( child.getLocalName() )
788 					&& ( ( ns == null && child.getNamespaceURI() == null ) || ( ns != null && ns.equals( child
789 							.getNamespaceURI() ) ) ) )
790 				ix++ ;
791 
792 			child = child.getNextSibling();
793 		}
794 
795 		throw new RuntimeException( "Child node not found in parent!?" );
796 	}
797 
798 	public static boolean setNodeValue( Node domNode, String string )
799 	{
800 		if( domNode == null )
801 			return false;
802 
803 		short nodeType = domNode.getNodeType();
804 
805 		switch( nodeType )
806 		{
807 		case Node.ELEMENT_NODE :
808 		{
809 			setElementText( ( Element )domNode, string );
810 			break;
811 		}
812 		case Node.ATTRIBUTE_NODE :
813 		case Node.TEXT_NODE :
814 		{
815 			domNode.setNodeValue( string );
816 			break;
817 		}
818 		case Node.PROCESSING_INSTRUCTION_NODE :
819 		{
820 			( ( ProcessingInstruction )domNode ).setData( string );
821 			break;
822 		}
823 		case Node.CDATA_SECTION_NODE :
824 		{
825 			( ( CDATASection )domNode ).setData( string );
826 			break;
827 		}
828 		default :
829 		{
830 			return false;
831 		}
832 		}
833 
834 		return true;
835 	}
836 
837 	public static String declareXPathNamespaces( XmlObject xmlObject )
838 	{
839 		Map<QName, String> map = new HashMap<QName, String>();
840 		XmlCursor cursor = xmlObject.newCursor();
841 
842 		while( cursor.hasNextToken() )
843 		{
844 			if( cursor.toNextToken().isNamespace() )
845 				map.put( cursor.getName(), cursor.getTextValue() );
846 		}
847 
848 		cursor.dispose();
849 
850 		Iterator<QName> i = map.keySet().iterator();
851 		int nsCnt = 0;
852 
853 		StringBuffer buf = new StringBuffer();
854 		Set<String> prefixes = new HashSet<String>();
855 		Set<String> usedPrefixes = new HashSet<String>();
856 
857 		while( i.hasNext() )
858 		{
859 			QName name = i.next();
860 			String prefix = name.getLocalPart();
861 			if( prefix.length() == 0 )
862 				prefix = "ns" + Integer.toString( ++nsCnt );
863 			else if( prefix.equals( "xsd" ) || prefix.equals( "xsi" ) )
864 				continue;
865 
866 			if( usedPrefixes.contains( prefix ) )
867 			{
868 				int c = 1;
869 				while( usedPrefixes.contains( prefix + c ) )
870 					c++ ;
871 
872 				prefix = prefix + Integer.toString( c );
873 			}
874 			else
875 				prefixes.add( prefix );
876 
877 			buf.append( "declare namespace " );
878 			buf.append( prefix );
879 			buf.append( "='" );
880 			buf.append( map.get( name ) );
881 			buf.append( "';\n" );
882 
883 			usedPrefixes.add( prefix );
884 		}
885 
886 		return buf.toString();
887 	}
888 
889 	public static String setXPathContent( String xmlText, String xpath, String value )
890 	{
891 		try
892 		{
893 			XmlObject xmlObject = XmlObject.Factory.parse( xmlText );
894 
895 			String namespaces = declareXPathNamespaces( xmlObject );
896 			if( namespaces != null && namespaces.trim().length() > 0 )
897 				xpath = namespaces + xpath;
898 
899 			XmlObject[] path = xmlObject.selectPath( xpath );
900 			for( XmlObject xml : path )
901 			{
902 				setNodeValue( xml.getDomNode(), value );
903 			}
904 
905 			return xmlObject.toString();
906 		}
907 		catch( Exception e )
908 		{
909 			SoapUI.logError( e );
910 		}
911 
912 		return xmlText;
913 	}
914 
915 	public static QName getQName( Node node )
916 	{
917 		if( node == null )
918 			return null;
919 		else if( node.getNamespaceURI() == null )
920 			return new QName( node.getNodeName() );
921 		else
922 			return new QName( node.getNamespaceURI(), node.getLocalName() );
923 	}
924 
925 	public static String removeXPathNamespaceDeclarations( String xpath )
926 	{
927 		while( xpath.startsWith( "declare namespace" ) )
928 		{
929 			int ix = xpath.indexOf( ';' );
930 			if( ix == -1 )
931 				break;
932 
933 			xpath = xpath.substring( ix + 1 ).trim();
934 		}
935 		return xpath;
936 	}
937 
938 	public static String stripWhitespaces( String content )
939 	{
940 		try
941 		{
942 			XmlObject xml = XmlObject.Factory.parse( content, new XmlOptions().setLoadStripWhitespace()
943 					.setLoadStripComments() );
944 			content = xml.xmlText();
945 		}
946 		catch( Exception e )
947 		{
948 			SoapUI.logError( e );
949 		}
950 
951 		return content;
952 	}
953 
954 	public static NodeList getChildElements( Element elm )
955 	{
956 		List<Element> list = new ArrayList<Element>();
957 
958 		NodeList nl = elm.getChildNodes();
959 		for( int c = 0; c < nl.getLength(); c++ )
960 		{
961 			Node item = nl.item( c );
962 			if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE )
963 				list.add( ( Element )item );
964 		}
965 
966 		return new ElementNodeList( list );
967 	}
968 
969 	public static NodeList getChildElementsByTagName( Element elm, String name )
970 	{
971 		List<Element> list = new ArrayList<Element>();
972 
973 		NodeList nl = elm.getChildNodes();
974 		for( int c = 0; c < nl.getLength(); c++ )
975 		{
976 			Node item = nl.item( c );
977 			if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE && name.equals( item.getNodeName() ) )
978 				list.add( ( Element )item );
979 		}
980 
981 		return new ElementNodeList( list );
982 	}
983 
984 	public static NodeList getChildElementsOfType( Element elm, SchemaType schemaType )
985 	{
986 		List<Element> list = new ArrayList<Element>();
987 
988 		NodeList nl = elm.getChildNodes();
989 		for( int c = 0; c < nl.getLength(); c++ )
990 		{
991 			Node item = nl.item( c );
992 			if( item.getParentNode() == elm
993 					&& item.getNodeType() == Node.ELEMENT_NODE
994 					&& ( ( Element )item ).getAttributeNS( Constants.XSI_NS, "type" ).endsWith(
995 							":" + schemaType.getName().getLocalPart() ) )
996 			{
997 				list.add( ( Element )item );
998 			}
999 		}
1000 
1001 		return new ElementNodeList( list );
1002 	}
1003 
1004 	public static NodeList getChildElementsNS( Element elm, QName name )
1005 	{
1006 		return getChildElementsByTagNameNS( elm, name.getNamespaceURI(), name.getLocalPart() );
1007 	}
1008 
1009 	public static NodeList getChildElementsByTagNameNS( Element elm, String namespaceUri, String localName )
1010 	{
1011 		List<Element> list = new ArrayList<Element>();
1012 
1013 		NodeList nl = elm.getChildNodes();
1014 		for( int c = 0; c < nl.getLength(); c++ )
1015 		{
1016 			Node item = nl.item( c );
1017 			if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE
1018 					&& localName.equals( item.getLocalName() ) && namespaceUri.equals( item.getNamespaceURI() ) )
1019 				list.add( ( Element )item );
1020 		}
1021 
1022 		return new ElementNodeList( list );
1023 	}
1024 
1025 	public static String serialize( Document document )
1026 	{
1027 		StringWriter writer = new StringWriter();
1028 		try
1029 		{
1030 			serialize( document, writer );
1031 		}
1032 		catch( IOException e )
1033 		{
1034 			e.printStackTrace();
1035 		}
1036 		return writer.toString();
1037 	}
1038 
1039 	public static Element getFirstChildElementNS( Element domNode, QName name )
1040 	{
1041 		return getFirstChildElementNS( domNode, name.getNamespaceURI(), name.getLocalPart() );
1042 	}
1043 
1044 	public static QName findTypeNameForXsiType( String typeName, Element elm )
1045 	{
1046 		int ix = typeName.indexOf( ':' );
1047 		if( ix == -1 )
1048 			return null;
1049 
1050 		String prefix = typeName.substring( 0, ix );
1051 		String localName = typeName.substring( ix + 1 );
1052 		String namespaceUri = elm.getAttribute( "xmlns:" + prefix );
1053 
1054 		if( !StringUtils.hasContent( namespaceUri ) )
1055 			namespaceUri = findNamespaceForPrefix( elm, prefix );
1056 
1057 		if( StringUtils.hasContent( namespaceUri ) )
1058 		{
1059 			return new QName( namespaceUri, localName );
1060 		}
1061 
1062 		return null;
1063 	}
1064 
1065 	private static String findNamespaceForPrefix( Element elm, String prefix )
1066 	{
1067 		String namespaceUri = null;
1068 		while( StringUtils.isNullOrEmpty( namespaceUri ) && elm != null )
1069 		{
1070 			if( elm.getParentNode().getNodeType() != Node.ELEMENT_NODE )
1071 				break;
1072 
1073 			elm = ( Element )elm.getParentNode();
1074 			namespaceUri = elm.getAttribute( "xmlns:" + prefix );
1075 		}
1076 
1077 		return StringUtils.isNullOrEmpty( namespaceUri ) ? null : namespaceUri;
1078 	}
1079 
1080 	public static String findPrefixForNamespace( Element elm, String namespace )
1081 	{
1082 		while( elm != null )
1083 		{
1084 			NamedNodeMap attributes = elm.getAttributes();
1085 			for( int c = 0; c < attributes.getLength(); c++ )
1086 			{
1087 				if( attributes.item( c ).getNodeValue().equals( namespace )
1088 						&& attributes.item( c ).getNodeName().startsWith( "xmlns:" ) )
1089 				{
1090 					return attributes.item( c ).getNodeName().substring( 6 );
1091 				}
1092 			}
1093 
1094 			if( elm.getParentNode().getNodeType() != Node.ELEMENT_NODE )
1095 				break;
1096 
1097 			elm = ( Element )elm.getParentNode();
1098 		}
1099 
1100 		return null;
1101 	}
1102 
1103 	public static void setXsiType( Element elm, QName name )
1104 	{
1105 		String prefix = findPrefixForNamespace( elm, name.getNamespaceURI() );
1106 		if( prefix == null )
1107 		{
1108 			prefix = generatePrefixForNamespace( name.getNamespaceURI() );
1109 			while( findNamespaceForPrefix( elm, prefix ) != null )
1110 			{
1111 				prefix = generatePrefixForNamespace( name.getNamespaceURI() );
1112 			}
1113 
1114 			elm.setAttribute( "xmlns:" + prefix, name.getNamespaceURI() );
1115 		}
1116 
1117 		elm.setAttributeNS( Constants.XSI_NS, "type", prefix + ":" + name.getLocalPart() );
1118 	}
1119 
1120 	private static String generatePrefixForNamespace( String namespaceURI )
1121 	{
1122 		return "ns" + ( int )( Math.random() * 1000 );
1123 	}
1124 
1125 	public static QName createQName( Node node )
1126 	{
1127 		return new QName( node.getNamespaceURI(), node.getLocalName() );
1128 	}
1129 
1130 	public static Node getNextElementSibling( Node node )
1131 	{
1132 		node = node.getNextSibling();
1133 		while( node != null && node.getNodeType() != Node.ELEMENT_NODE )
1134 		{
1135 			node = node.getNextSibling();
1136 		}
1137 
1138 		return node;
1139 	}
1140 
1141 	public static Document createDocument( QName element )
1142 	{
1143 		ensureDocumentBuilder();
1144 
1145 		Document document = documentBuilder.newDocument();
1146 		document.appendChild( document.createElementNS( element.getNamespaceURI(), element.getLocalPart() ) );
1147 		return document;
1148 	}
1149 
1150 	public static String getValueForMatch( XmlCursor cursor )
1151 	{
1152 		Node domNode = cursor.getDomNode();
1153 		String stringValue;
1154 
1155 		if( domNode.getNodeType() == Node.ATTRIBUTE_NODE || domNode.getNodeType() == Node.TEXT_NODE )
1156 		{
1157 			stringValue = domNode.getNodeValue();
1158 		}
1159 		else if( cursor.getObject() instanceof XmlAnySimpleType )
1160 		{
1161 			stringValue = ( ( XmlAnySimpleType )cursor.getObject() ).getStringValue();
1162 		}
1163 		else
1164 		{
1165 			if( domNode.getNodeType() == Node.ELEMENT_NODE )
1166 			{
1167 				Element elm = ( Element )domNode;
1168 				if( elm.getChildNodes().getLength() == 1 && !hasContentAttributes( elm ) )
1169 				{
1170 					stringValue = getElementText( elm );
1171 				}
1172 				else
1173 				{
1174 					stringValue = cursor.getObject().xmlText(
1175 							new XmlOptions().setSavePrettyPrint().setSaveOuter().setSaveAggressiveNamespaces() );
1176 				}
1177 			}
1178 			else
1179 			{
1180 				stringValue = domNode.getNodeValue();
1181 			}
1182 		}
1183 		return stringValue;
1184 	}
1185 
1186 	public static boolean hasContentAttributes( Element elm )
1187 	{
1188 		NamedNodeMap attributes = elm.getAttributes();
1189 		for( int c = 0; c < attributes.getLength(); c++ )
1190 		{
1191 			Node item = attributes.item( c );
1192 			String ns = item.getNamespaceURI();
1193 			if( !ns.equals( Constants.XML_NS )
1194 			// && !ns.equals( Constants.XSI_NS ) && !ns.equals(
1195 			// Constants.XSI_NS_2000 )
1196 			// && !ns.equals( Constants.XSD_NS )
1197 			)
1198 				return true;
1199 		}
1200 
1201 		return false;
1202 	}
1203 
1204 	public static String getValueForMatch( Node domNode, boolean prettyPrintXml )
1205 	{
1206 		String stringValue;
1207 
1208 		if( domNode.getNodeType() == Node.ATTRIBUTE_NODE || domNode.getNodeType() == Node.TEXT_NODE )
1209 		{
1210 			stringValue = domNode.getNodeValue();
1211 		}
1212 		else
1213 		{
1214 			if( domNode.getNodeType() == Node.ELEMENT_NODE )
1215 			{
1216 				Element elm = ( Element )domNode;
1217 				if( elm.getChildNodes().getLength() == 1 && !hasContentAttributes( elm ) )
1218 				{
1219 					stringValue = getElementText( elm );
1220 				}
1221 				else
1222 				{
1223 					stringValue = XmlUtils.serialize( domNode, prettyPrintXml );
1224 				}
1225 			}
1226 			else
1227 			{
1228 				stringValue = domNode.getNodeValue();
1229 			}
1230 		}
1231 
1232 		return stringValue;
1233 	}
1234 
1235 	public static String selectFirstNodeValue( XmlObject xmlObject, String xpath ) throws XmlException
1236 	{
1237 		Node domNode = selectFirstDomNode( xmlObject, xpath );
1238 		return domNode == null ? null : getNodeValue( domNode );
1239 	}
1240 
1241 	public static String[] selectNodeValues( XmlObject xmlObject, String xpath )
1242 	{
1243 		Node[] nodes = selectDomNodes( xmlObject, xpath );
1244 
1245 		String[] result = new String[nodes.length];
1246 		for( int c = 0; c < nodes.length; c++ )
1247 		{
1248 			result[c] = getNodeValue( nodes[c] );
1249 		}
1250 
1251 		return result;
1252 	}
1253 
1254 	public static Node selectFirstDomNode( XmlObject xmlObject, String xpath )
1255 	{
1256 		XmlCursor cursor = xmlObject.newCursor();
1257 		try
1258 		{
1259 			cursor.selectPath( xpath );
1260 
1261 			if( cursor.toNextSelection() )
1262 			{
1263 				return cursor.getDomNode();
1264 			}
1265 			else
1266 				return null;
1267 		}
1268 		finally
1269 		{
1270 			cursor.dispose();
1271 		}
1272 	}
1273 
1274 	public static Node[] selectDomNodes( XmlObject xmlObject, String xpath )
1275 	{
1276 		List<Node> result = new ArrayList<Node>();
1277 
1278 		XmlCursor cursor = xmlObject.newCursor();
1279 		try
1280 		{
1281 			cursor.selectPath( xpath );
1282 
1283 			while( cursor.toNextSelection() )
1284 			{
1285 				result.add( cursor.getDomNode() );
1286 			}
1287 		}
1288 		finally
1289 		{
1290 			cursor.dispose();
1291 		}
1292 
1293 		return result.toArray( new Node[result.size()] );
1294 	}
1295 
1296 	private final static class ElementNodeList implements NodeList
1297 	{
1298 		private final List<Element> list;
1299 
1300 		public ElementNodeList( List<Element> list )
1301 		{
1302 			this.list = list;
1303 		}
1304 
1305 		public int getLength()
1306 		{
1307 			return list.size();
1308 		}
1309 
1310 		public Node item( int index )
1311 		{
1312 			return list.get( index );
1313 		}
1314 	}
1315 
1316 	public static boolean seemsToBeXml( String str )
1317 	{
1318 		try
1319 		{
1320 			if( StringUtils.isNullOrEmpty( str ) )
1321 				return false;
1322 
1323 			return null != XmlObject.Factory.parse( str );
1324 		}
1325 		catch( Throwable e )
1326 		{
1327 			return false;
1328 		}
1329 	}
1330 
1331 	public static String extractNamespaces( String xpath )
1332 	{
1333 		String result = xpath;
1334 		int ix = xpath.lastIndexOf( "declare namespace" );
1335 		if( ix != -1 )
1336 		{
1337 			ix = xpath.indexOf( '\'', ix + 1 );
1338 			if( ix != -1 )
1339 			{
1340 				ix = xpath.indexOf( '\'', ix + 1 );
1341 				if( ix != -1 )
1342 				{
1343 					ix = xpath.indexOf( ';' );
1344 					if( ix != -1 )
1345 					{
1346 						result = xpath.substring( 0, ix + 1 );
1347 					}
1348 				}
1349 			}
1350 		}
1351 		else
1352 		{
1353 			result = "";
1354 		}
1355 
1356 		return result;
1357 	}
1358 
1359 	public static String removeUnneccessaryNamespaces( String xml )
1360 	{
1361 		if( StringUtils.isNullOrEmpty( xml ) )
1362 			return xml;
1363 
1364 		XmlObject xmlObject = null;
1365 		XmlCursor cursor = null;
1366 		try
1367 		{
1368 			xmlObject = XmlObject.Factory.parse( xml );
1369 
1370 			cursor = xmlObject.newCursor();
1371 			while( cursor.currentTokenType() != TokenType.START && cursor.currentTokenType() != TokenType.ENDDOC )
1372 			{
1373 				cursor.toNextToken();
1374 			}
1375 
1376 			if( cursor.currentTokenType() == TokenType.START )
1377 			{
1378 				Map<?, ?> nsMap = new HashMap<Object, Object>();
1379 
1380 				cursor.getAllNamespaces( nsMap );
1381 				nsMap.remove( cursor.getDomNode().getPrefix() );
1382 
1383 				NamedNodeMap attributes = cursor.getDomNode().getAttributes();
1384 				for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
1385 				{
1386 					nsMap.remove( attributes.item( c ).getPrefix() );
1387 				}
1388 
1389 				if( cursor.toFirstChild() )
1390 				{
1391 					while( cursor.getDomNode() != xmlObject.getDomNode() )
1392 					{
1393 						attributes = cursor.getDomNode().getAttributes();
1394 						for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
1395 						{
1396 							nsMap.remove( attributes.item( c ).getPrefix() );
1397 						}
1398 
1399 						nsMap.remove( cursor.getDomNode().getPrefix() );
1400 						cursor.toNextToken();
1401 					}
1402 				}
1403 
1404 				xml = xmlObject.xmlText( new XmlOptions().setSaveOuter().setSavePrettyPrint()
1405 						.setSaveImplicitNamespaces( nsMap ) );
1406 			}
1407 		}
1408 		catch( XmlException e )
1409 		{
1410 
1411 		}
1412 		finally
1413 		{
1414 			if( cursor != null )
1415 				cursor.dispose();
1416 		}
1417 
1418 		return xml;
1419 	}
1420 
1421 	public static String replaceNameInPathOrQuery( String pathOrQuery, String oldName, String newName ) throws Exception
1422 	{
1423 		Tokenizer t = new Tokenizer();
1424 		t.tokenize( pathOrQuery, 0, -1, 1 );
1425 		StringBuffer result = new StringBuffer();
1426 		int lastIx = 0;
1427 
1428 		while( t.currentToken != Token.EOF )
1429 		{
1430 			if( t.currentToken == Token.NAME && t.currentTokenValue.equals( oldName ) )
1431 			{
1432 				result.append( pathOrQuery.substring( lastIx, t.currentTokenStartOffset ) );
1433 				result.append( newName );
1434 				lastIx = t.currentTokenStartOffset + t.currentTokenValue.length();
1435 			}
1436 
1437 			t.next();
1438 		}
1439 
1440 		if( lastIx < pathOrQuery.length() )
1441 			result.append( pathOrQuery.substring( lastIx ) );
1442 		//
1443 		System.out.println( "returning " + result.toString() );
1444 		return result.toString();
1445 	}
1446 
1447 	public static QName getQName( XmlObject contentElement )
1448 	{
1449 		return contentElement == null ? null : getQName( contentElement.getDomNode() );
1450 	}
1451 
1452 	public static String getXPathValue( String value, String xpath )
1453 	{
1454 		try
1455 		{
1456 			XmlObject xmlObject = XmlObject.Factory.parse( value );
1457 			XmlObject[] nodes = xmlObject.selectPath( xpath );
1458 			if( nodes.length > 0 )
1459 				return getNodeValue( nodes[0].getDomNode() );
1460 		}
1461 		catch( XmlException e )
1462 		{
1463 			e.printStackTrace();
1464 		}
1465 
1466 		return null;
1467 	}
1468 
1469 	public static String createJdbcXmlResult( Statement statement ) throws SQLException, ParserConfigurationException
1470 	{
1471 		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1472 		DocumentBuilder builder = factory.newDocumentBuilder();
1473 		org.w3c.dom.Document xmlDocumentResult = builder.newDocument();
1474 		Element resultsElement = xmlDocumentResult.createElement( "Results" );
1475 		xmlDocumentResult.appendChild( resultsElement );
1476 
1477 		if( statement != null )
1478 		{
1479 			ResultSet resultSet = statement.getResultSet();
1480 			if( resultSet != null )
1481 			{
1482 				resultSet.setFetchSize( statement.getFetchSize() );
1483 				xmlDocumentResult = addResultSetXmlPart( resultsElement, resultSet, xmlDocumentResult );
1484 				while( statement.getMoreResults() )
1485 				{
1486 					xmlDocumentResult = addResultSetXmlPart( resultsElement, statement.getResultSet(), xmlDocumentResult );
1487 				}
1488 			}
1489 			else
1490 			{
1491 				Element errorElement = xmlDocumentResult.createElement( "UpdateCount" );
1492 				errorElement.appendChild( xmlDocumentResult.createTextNode( String.valueOf( statement.getUpdateCount() ) ) );
1493 				resultsElement.appendChild( errorElement );
1494 			}
1495 		}
1496 
1497 		StringWriter out = new StringWriter();
1498 
1499 		OutputFormat outputFormat = new OutputFormat( xmlDocumentResult );
1500 		outputFormat.setOmitComments( true );
1501 		outputFormat.setOmitDocumentType( true );
1502 		outputFormat.setOmitXMLDeclaration( true );
1503 		// outputFormat.setLineSeparator( "\n" );
1504 		// add this line //
1505 		// outputFormat.setPreserveSpace( true );
1506 		outputFormat.setIndent( 3 );
1507 		outputFormat.setIndenting( true );
1508 
1509 		try
1510 		{
1511 			XMLSerializer serializer = new XMLSerializer( new PrintWriter( out ), outputFormat );
1512 			serializer.asDOMSerializer();
1513 			serializer.serialize( xmlDocumentResult );
1514 		}
1515 		catch( IOException e )
1516 		{
1517 			SoapUI.logError( e );
1518 		}
1519 
1520 		return out.toString();
1521 	}
1522 
1523 	public static Document addResultSetXmlPart( Element resultsElement, ResultSet rs, Document xmlDocumentResult )
1524 			throws SQLException
1525 	{
1526 		// resultSet = statement.getResultSet();
1527 		// connection to an ACCESS MDB
1528 		ResultSetMetaData rsmd = rs.getMetaData();
1529 		Element resultSetElement = xmlDocumentResult.createElement( "ResultSet" );
1530 
1531 		resultSetElement.setAttribute( "fetchSize", String.valueOf( rs.getFetchSize() ) );
1532 		resultsElement.appendChild( resultSetElement );
1533 
1534 		int colCount = rsmd.getColumnCount();
1535 		while( rs.next() )
1536 		{
1537 			Element rowElement = xmlDocumentResult.createElement( "Row" );
1538 			rowElement.setAttribute( "rowNumber", String.valueOf( rs.getRow() ) );
1539 
1540 			resultsElement.appendChild( rowElement );
1541 			for( int ii = 1; ii <= colCount; ii++ )
1542 			{
1543 				String columnName = "";
1544 				if( !StringUtils.isNullOrEmpty( rsmd.getTableName( ii ) ) )
1545 				{
1546 					columnName += ( rsmd.getTableName( ii ) ).toUpperCase() + ".";
1547 				}
1548 				columnName += ( rsmd.getColumnName( ii ) ).toUpperCase();
1549 				String value = rs.getString( ii );
1550 				Element node = xmlDocumentResult.createElement( StringUtils.createXmlName( columnName ) );
1551 				if( !StringUtils.isNullOrEmpty( value ) )
1552 				{
1553 					Text textNode = xmlDocumentResult.createTextNode( value.toString() );
1554 					node.appendChild( textNode );
1555 				}
1556 				rowElement.appendChild( node );
1557 			}
1558 			resultSetElement.appendChild( rowElement );
1559 		}
1560 		return xmlDocumentResult;
1561 	}
1562 
1563 }