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