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.setAttributeNodeNS( (Attr) elm2.getOwnerDocument().importNode( attr, true ) );
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
714 switch( nodeType )
715 {
716 case Node.ELEMENT_NODE:
717 {
718 setElementText( (Element) domNode, string );
719 break;
720 }
721 case Node.ATTRIBUTE_NODE:
722 case Node.TEXT_NODE:
723 {
724 domNode.setNodeValue( string );
725 break;
726 }
727 case Node.PROCESSING_INSTRUCTION_NODE:
728 {
729 ( (ProcessingInstruction) domNode ).setData( string );
730 break;
731 }
732 case Node.CDATA_SECTION_NODE:
733 {
734 ( (CDATASection) domNode ).setData( string );
735 break;
736 }
737 default:
738 {
739 return false;
740 }
741 }
742
743 return true;
744 }
745
746 public static String declareXPathNamespaces( XmlObject xmlObject )
747 {
748 Map<QName, String> map = new HashMap<QName, String>();
749 XmlCursor cursor = xmlObject.newCursor();
750
751 while( cursor.hasNextToken() )
752 {
753 if( cursor.toNextToken().isNamespace() )
754 map.put( cursor.getName(), cursor.getTextValue() );
755 }
756
757 Iterator<QName> i = map.keySet().iterator();
758 int nsCnt = 0;
759
760 StringBuffer buf = new StringBuffer();
761 Set<String> prefixes = new HashSet<String>();
762 Set<String> usedPrefixes = new HashSet<String>();
763
764 while( i.hasNext() )
765 {
766 QName name = i.next();
767 String prefix = name.getLocalPart();
768 if( prefix.length() == 0 ) prefix = "ns" + Integer.toString( ++nsCnt );
769 else if( prefix.equals( "xsd" ) || prefix.equals( "xsi" ) ) continue;
770
771 if( usedPrefixes.contains( prefix ) )
772 {
773 int c = 1;
774 while( usedPrefixes.contains( prefix + c ) ) c++;
775
776 prefix = prefix + Integer.toString( c );
777 }
778 else prefixes.add( prefix );
779
780 buf.append( "declare namespace " );
781 buf.append( prefix );
782 buf.append( "='" );
783 buf.append( map.get( name ) );
784 buf.append( "';\n" );
785
786 usedPrefixes.add( prefix );
787 }
788
789 return buf.toString();
790 }
791
792 public static String setXPathContent( String xmlText, String xpath, String value )
793 {
794 try
795 {
796 XmlObject xmlObject = XmlObject.Factory.parse( xmlText );
797
798 String namespaces = declareXPathNamespaces( xmlObject );
799 if( namespaces != null && namespaces.trim().length() > 0 )
800 xpath = namespaces + xpath;
801
802 XmlObject[] path = xmlObject.selectPath( xpath );
803 for( XmlObject xml : path )
804 {
805 setNodeValue( xml.getDomNode(), value );
806 }
807
808 return xmlObject.toString();
809 }
810 catch( Exception e )
811 {
812 SoapUI.logError( e );
813 }
814
815 return xmlText;
816 }
817
818 public static QName getQName( Node node )
819 {
820 if( node.getNamespaceURI() == null )
821 return new QName( node.getNodeName() );
822 else
823 return new QName( node.getNamespaceURI(), node.getLocalName() );
824 }
825
826 public static String removeXPathNamespaceDeclarations( String xpath )
827 {
828 while( xpath.startsWith( "declare namespace" ) )
829 {
830 int ix = xpath.indexOf( ';' );
831 if( ix == -1 )
832 break;
833
834 xpath = xpath.substring( ix + 1 ).trim();
835 }
836 return xpath;
837 }
838
839 public static String stripWhitespaces( String content )
840 {
841 try
842 {
843 XmlObject xml = XmlObject.Factory.parse( content, new XmlOptions().setLoadStripWhitespace().setLoadStripComments() );
844 content = xml.xmlText();
845 }
846 catch( Exception e )
847 {
848 SoapUI.logError( e );
849 }
850
851 return content;
852 }
853
854 public static NodeList getChildElements( Element elm )
855 {
856 List<Element> list = new ArrayList<Element>();
857
858 NodeList nl = elm.getChildNodes();
859 for( int c = 0; c < nl.getLength(); c++ )
860 {
861 Node item = nl.item( c );
862 if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE )
863 list.add( (Element) item );
864 }
865
866 return new ElementNodeList( list );
867 }
868
869 public static NodeList getChildElementsByTagName( Element elm, String name )
870 {
871 List<Element> list = new ArrayList<Element>();
872
873 NodeList nl = elm.getChildNodes();
874 for( int c = 0; c < nl.getLength(); c++ )
875 {
876 Node item = nl.item( c );
877 if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE && name.equals( item.getNodeName() ) )
878 list.add( (Element) item );
879 }
880
881 return new ElementNodeList( list );
882 }
883
884 public static NodeList getChildElementsOfType( Element elm, SchemaType schemaType )
885 {
886 List<Element> list = new ArrayList<Element>();
887
888 NodeList nl = elm.getChildNodes();
889 for( int c = 0; c < nl.getLength(); c++ )
890 {
891 Node item = nl.item( c );
892 if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE &&
893 ( (Element) item ).getAttributeNS( Constants.XSI_NS, "type" ).endsWith( ":" + schemaType.getName().getLocalPart() ) )
894 {
895 list.add( (Element) item );
896 }
897 }
898
899 return new ElementNodeList( list );
900 }
901
902 public static NodeList getChildElementsNS( Element elm, QName name )
903 {
904 return getChildElementsByTagNameNS( elm, name.getNamespaceURI(), name.getLocalPart() );
905 }
906
907 public static NodeList getChildElementsByTagNameNS( Element elm, String namespaceUri, String localName )
908 {
909 List<Element> list = new ArrayList<Element>();
910
911 NodeList nl = elm.getChildNodes();
912 for( int c = 0; c < nl.getLength(); c++ )
913 {
914 Node item = nl.item( c );
915 if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE &&
916 localName.equals( item.getLocalName() ) && namespaceUri.equals( item.getNamespaceURI() ) )
917 list.add( (Element) item );
918 }
919
920 return new ElementNodeList( list );
921 }
922
923 public static String serialize( Document document )
924 {
925 StringWriter writer = new StringWriter();
926 try
927 {
928 serialize( document, writer );
929 }
930 catch( IOException e )
931 {
932 e.printStackTrace();
933 }
934 return writer.toString();
935 }
936
937 public static Element getFirstChildElementNS( Element domNode, QName name )
938 {
939 return getFirstChildElementNS( domNode, name.getNamespaceURI(), name.getLocalPart() );
940 }
941
942 public static QName findTypeNameForXsiType( String typeName, Element elm )
943 {
944 int ix = typeName.indexOf( ':' );
945 if( ix == -1 )
946 return null;
947
948 String prefix = typeName.substring( 0, ix );
949 String localName = typeName.substring( ix + 1 );
950 String namespaceUri = elm.getAttribute( "xmlns:" + prefix );
951
952 if( !StringUtils.hasContent( namespaceUri ) )
953 namespaceUri = findNamespaceForPrefix( elm, prefix );
954
955 if( StringUtils.hasContent( namespaceUri ) )
956 {
957 return new QName( namespaceUri, localName );
958 }
959
960 return null;
961 }
962
963 private static String findNamespaceForPrefix( Element elm, String prefix )
964 {
965 String namespaceUri = null;
966 while( StringUtils.isNullOrEmpty( namespaceUri ) && elm != null )
967 {
968 if( elm.getParentNode().getNodeType() != Node.ELEMENT_NODE )
969 break;
970
971 elm = (Element) elm.getParentNode();
972 namespaceUri = elm.getAttribute( "xmlns:" + prefix );
973 }
974
975 return StringUtils.isNullOrEmpty( namespaceUri ) ? null : namespaceUri;
976 }
977
978 public static String findPrefixForNamespace( Element elm, String namespace )
979 {
980 while( elm != null )
981 {
982 NamedNodeMap attributes = elm.getAttributes();
983 for( int c = 0; c < attributes.getLength(); c++ )
984 {
985 if( attributes.item( c ).getNodeValue().equals( namespace ) &&
986 attributes.item( c ).getNodeName().startsWith( "xmlns:" ) )
987 {
988 return attributes.item( c ).getNodeName().substring( 6 );
989 }
990 }
991
992 if( elm.getParentNode().getNodeType() != Node.ELEMENT_NODE )
993 break;
994
995 elm = (Element) elm.getParentNode();
996 }
997
998 return null;
999 }
1000
1001 public static void setXsiType( Element elm, QName name )
1002 {
1003 String prefix = findPrefixForNamespace( elm, name.getNamespaceURI() );
1004 if( prefix == null )
1005 {
1006 prefix = generatePrefixForNamespace( name.getNamespaceURI() );
1007 int cnt = 1;
1008 while( findNamespaceForPrefix( elm, prefix ) != null )
1009 {
1010 prefix = generatePrefixForNamespace( name.getNamespaceURI() );
1011 }
1012
1013 elm.setAttribute( "xmlns:" + prefix, name.getNamespaceURI() );
1014 }
1015
1016 elm.setAttributeNS( Constants.XSI_NS, "type", prefix + ":" + name.getLocalPart() );
1017 }
1018
1019 private static String generatePrefixForNamespace( String namespaceURI )
1020 {
1021 return "ns" + (int) ( Math.random() * 1000 );
1022 }
1023
1024 public static QName createQName( Node node )
1025 {
1026 return new QName( node.getNamespaceURI(), node.getLocalName() );
1027 }
1028
1029 public static Node getNextElementSibling( Node node )
1030 {
1031 node = node.getNextSibling();
1032 while( node != null && node.getNodeType() != Node.ELEMENT_NODE )
1033 {
1034 node = node.getNextSibling();
1035 }
1036
1037 return node;
1038 }
1039
1040 public static Document createDocument( QName element )
1041 {
1042 ensureDocumentBuilder();
1043
1044 Document document = documentBuilder.newDocument();
1045 document.appendChild( document.createElementNS( element.getNamespaceURI(), element.getLocalPart() ) );
1046 return document;
1047 }
1048
1049 public static String getValueForMatch( XmlCursor cursor )
1050 {
1051 Node domNode = cursor.getDomNode();
1052 String stringValue;
1053
1054 if( domNode.getNodeType() == Node.ATTRIBUTE_NODE || domNode.getNodeType() == Node.TEXT_NODE )
1055 {
1056 stringValue = domNode.getNodeValue();
1057 }
1058 else if( cursor.getObject() instanceof XmlAnySimpleType )
1059 {
1060 stringValue = ( (XmlAnySimpleType) cursor.getObject() ).getStringValue();
1061 }
1062 else
1063 {
1064 if( domNode.getNodeType() == Node.ELEMENT_NODE )
1065 {
1066 Element elm = (Element) domNode;
1067 if( elm.getChildNodes().getLength() == 1 && elm.getAttributes().getLength() == 0 )
1068 {
1069 stringValue = getElementText( elm );
1070 }
1071 else
1072 {
1073 stringValue = cursor.getObject().xmlText( new XmlOptions().setSavePrettyPrint().setSaveOuter().setSaveAggressiveNamespaces() );
1074 }
1075 }
1076 else
1077 {
1078 stringValue = domNode.getNodeValue();
1079 }
1080 }
1081 return stringValue;
1082 }
1083
1084 private final static class ElementNodeList implements NodeList
1085 {
1086 private final List<Element> list;
1087
1088 public ElementNodeList( List<Element> list )
1089 {
1090 this.list = list;
1091 }
1092
1093 public int getLength()
1094 {
1095 return list.size();
1096 }
1097
1098 public Node item( int index )
1099 {
1100 return list.get( index );
1101 }
1102 }
1103
1104 public static boolean seemsToBeXml( String str )
1105 {
1106 try
1107 {
1108 if( StringUtils.isNullOrEmpty( str ) )
1109 return false;
1110
1111 return XmlObject.Factory.parse( str ) != null;
1112 }
1113 catch( Exception e )
1114 {
1115 return false;
1116 }
1117 }
1118
1119 public static String extractNamespaces( String xpath )
1120 {
1121 String result = xpath;
1122 int ix = xpath.lastIndexOf( "declare namespace" );
1123 if( ix != -1 )
1124 {
1125 ix = xpath.indexOf( '\'', ix + 1 );
1126 if( ix != -1 )
1127 {
1128 ix = xpath.indexOf( '\'', ix + 1 );
1129 if( ix != -1 )
1130 {
1131 ix = xpath.indexOf( ';' );
1132 if( ix != -1 )
1133 {
1134 result = xpath.substring( 0, ix + 1 );
1135 }
1136 }
1137 }
1138 }
1139 else
1140 {
1141 result = "";
1142 }
1143
1144 return result;
1145 }
1146
1147 public static String removeUnneccessaryNamespaces( String xml )
1148 {
1149 if( StringUtils.isNullOrEmpty( xml ) )
1150 return xml;
1151
1152 XmlObject xmlObject = null;
1153 XmlCursor cursor = null;
1154 try
1155 {
1156 xmlObject = XmlObject.Factory.parse( xml );
1157
1158 cursor = xmlObject.newCursor();
1159 while( cursor.currentTokenType() != TokenType.START && cursor.currentTokenType() != TokenType.ENDDOC )
1160 {
1161 cursor.toNextToken();
1162 }
1163
1164 if( cursor.currentTokenType() == TokenType.START )
1165 {
1166 Map<?, ?> nsMap = new HashMap<Object, Object>();
1167
1168 cursor.getAllNamespaces( nsMap );
1169 nsMap.remove( cursor.getDomNode().getPrefix() );
1170
1171 NamedNodeMap attributes = cursor.getDomNode().getAttributes();
1172 for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
1173 {
1174 nsMap.remove( attributes.item( c ).getPrefix() );
1175 }
1176
1177 if( cursor.toFirstChild() )
1178 {
1179 while( cursor.getDomNode() != xmlObject.getDomNode() )
1180 {
1181 attributes = cursor.getDomNode().getAttributes();
1182 for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
1183 {
1184 nsMap.remove( attributes.item( c ).getPrefix() );
1185 }
1186
1187 nsMap.remove( cursor.getDomNode().getPrefix() );
1188 cursor.toNextToken();
1189 }
1190 }
1191
1192 xml = xmlObject.xmlText( new XmlOptions().setSaveOuter().setSavePrettyPrint()
1193 .setSaveImplicitNamespaces( nsMap ) );
1194 }
1195 }
1196 catch( XmlException e )
1197 {
1198
1199 }
1200 finally
1201 {
1202 if( cursor != null )
1203 cursor.dispose();
1204 }
1205
1206 return xml;
1207 }
1208
1209 public static String replaceNameInPathOrQuery( String pathOrQuery, String oldName, String newName ) throws Exception
1210 {
1211 Tokenizer t = new Tokenizer();
1212 t.tokenize( pathOrQuery, 0, -1, 1 );
1213 StringBuffer result = new StringBuffer();
1214 int lastIx = 0;
1215
1216 while( t.currentToken != Token.EOF )
1217 {
1218 if( t.currentToken == Token.NAME && t.currentTokenValue.equals( oldName ) )
1219 {
1220 result.append( pathOrQuery.substring( lastIx, t.currentTokenStartOffset ) );
1221 result.append( newName );
1222 lastIx = t.currentTokenStartOffset + t.currentTokenValue.length();
1223 }
1224
1225 t.next();
1226 }
1227
1228 if( lastIx < pathOrQuery.length() )
1229 result.append( pathOrQuery.substring( lastIx ) );
1230
1231 System.out.println( "returning " + result.toString() );
1232 return result.toString();
1233 }
1234 }
1235