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