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