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