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