1
2
3
4
5
6
7
8
9
10
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( "&", "&" ).replaceAll( "<", "<" ).replaceAll( ">", ">" )
114 .replaceAll( "\"", """ ).replaceAll( "'", "'" );
115 }
116
117 public static String entitizeContent( String xml )
118 {
119 return xml.replaceAll( "&", "&" ).replaceAll( "\"", """ ).replaceAll( "'", "'" );
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
189
190
191
192
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
454 transferAttributes( elm, elm2 );
455
456
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
470 transferAttributes( elm, elm2 );
471
472
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
655
656
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
680
681
682
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
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
1195
1196
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
1504
1505
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
1527
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 }