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 if( node.getNodeType() == Node.ATTRIBUTE_NODE )
574 {
575 if( namespaceURI.length() > 0 )
576 {
577 String prefix = node.getPrefix();
578 if( prefix == null || prefix.length() == 0 )
579 prefix = "ns" + nsCnt++;
580
581 nsMap.put( namespaceURI, prefix );
582 pathComponents.add( "@" + prefix + ":" + node.getLocalName() );
583 }
584 else
585 {
586 pathComponents.add( "@" + node.getLocalName() );
587 }
588 node = ((Attr)node).getOwnerElement();
589 }
590 else if( node.getNodeType() == Node.DOCUMENT_NODE )
591 {
592 node = ((Document)node).getDocumentElement();
593 }
594
595
596
597
598
599 if( node.getNodeType() == Node.ELEMENT_NODE )
600 {
601 int index = anonymous ? 0 : findNodeIndex( node );
602
603 String pc = null;
604
605 namespaceURI = node.getNamespaceURI();
606 if( namespaceURI.length() > 0 )
607 {
608 String prefix = node.getPrefix();
609 if( prefix == null || prefix.length() == 0 )
610 prefix = "ns" + nsCnt++;
611
612 nsMap.put( namespaceURI, prefix );
613 pc = prefix + ":" + node.getLocalName();
614 }
615 else
616 {
617 pc = node.getLocalName();
618 }
619
620 String elementText = XmlUtils.getElementText( (Element) node );
621
622
623 if( selectText && pathComponents.isEmpty() && elementText != null && elementText.trim().length() > 0 )
624 pathComponents.add( "text()" );
625
626 pathComponents.add( pc + ((index == 0 ) ? "" : "[" + index + "]" ));
627 }
628 else
629 return null;
630
631 node = node.getParentNode();
632 namespaceURI = node.getNamespaceURI();
633 while( node != null && node.getNodeType() == Node.ELEMENT_NODE &&
634 (absolute ||
635 (!"Body".equals(node.getNodeName()) &&
636 !SoapVersion.Soap11.getEnvelopeNamespace().equals(namespaceURI) &&
637 !SoapVersion.Soap12.getEnvelopeNamespace().equals(namespaceURI) ) ) )
638 {
639 int index = anonymous ? 0 : findNodeIndex( node );
640
641 String ns = nsMap.get( namespaceURI );
642 String pc = null;
643
644 if( ns == null && namespaceURI.length() > 0 )
645 {
646 String prefix = node.getPrefix();
647 if( prefix == null || prefix.length() == 0 )
648 prefix = "ns" + nsCnt++;
649
650 nsMap.put( namespaceURI, prefix );
651 ns = nsMap.get( namespaceURI );
652
653 pc = prefix + ":" + node.getLocalName();
654 }
655 else if( ns != null )
656 {
657 pc = ns + ":" + node.getLocalName();
658 }
659 else
660 {
661 pc = node.getLocalName();
662 }
663
664 pathComponents.add( pc + ((index == 0 ) ? "" : "[" + index + "]" ));
665 node = node.getParentNode();
666 namespaceURI = node.getNamespaceURI();
667 }
668
669 return new XPathData(nsMap, pathComponents, absolute);
670 }
671
672 private static int findNodeIndex(Node node)
673 {
674 String nm = node.getLocalName();
675 String ns = node.getNamespaceURI();
676 short nt = node.getNodeType();
677
678 Node parentNode = node.getParentNode();
679 if( parentNode.getNodeType() != Node.ELEMENT_NODE )
680 return 1;
681
682 Node child = parentNode.getFirstChild();
683
684 int ix = 0;
685 while( child != null )
686 {
687 if( child == node )
688 return ix+1;
689
690 if( child.getNodeType() == nt &&
691 nm.equals( child.getNodeName() ) && ns.equals( child.getNamespaceURI()))
692 ix++;
693
694 child = child.getNextSibling();
695 }
696
697 throw new RuntimeException( "Child node not found in parent!?" );
698 }
699
700 public static boolean setNodeValue( Node domNode, String string )
701 {
702 short nodeType = domNode.getNodeType();
703 if( nodeType == Node.ELEMENT_NODE )
704 {
705 setElementText( ( Element ) domNode, string );
706 return true;
707 }
708 else if( nodeType == Node.ATTRIBUTE_NODE || nodeType == Node.TEXT_NODE )
709 {
710 domNode.setNodeValue( string );
711 return true;
712 }
713
714 return false;
715 }
716
717 public static String declareXPathNamespaces( XmlObject xmlObject )
718 {
719 Map<QName,String> map = new HashMap<QName,String>();
720 XmlCursor cursor = xmlObject.newCursor();
721
722 while( cursor.hasNextToken() )
723 {
724 if( cursor.toNextToken().isNamespace() )
725 map.put( cursor.getName(), cursor.getTextValue() );
726 }
727
728 Iterator<QName> i = map.keySet().iterator();
729 int nsCnt = 0;
730
731 StringBuffer buf = new StringBuffer();
732 Set<String> prefixes = new HashSet<String>();
733 Set<String> usedPrefixes = new HashSet<String>();
734
735 while( i.hasNext() )
736 {
737 QName name = i.next();
738 String prefix = name.getLocalPart();
739 if( prefix.length() == 0 ) prefix = "ns" + Integer.toString( ++nsCnt );
740 else if( prefix.equals( "xsd") || prefix.equals( "xsi")) continue;
741
742 if( usedPrefixes.contains( prefix ))
743 {
744 int c = 1;
745 while( usedPrefixes.contains( prefix + c )) c++;
746
747 prefix = prefix + Integer.toString( c );
748 }
749 else prefixes.add( prefix );
750
751 buf.append( "declare namespace " );
752 buf.append( prefix );
753 buf.append( "='" );
754 buf.append( map.get( name ));
755 buf.append( "';\n");
756
757 usedPrefixes.add( prefix );
758 }
759
760 return buf.toString();
761 }
762
763 public static String setXPathContent( String emptyResponse, String string, String actor )
764 {
765 try
766 {
767 XmlObject xmlObject = XmlObject.Factory.parse( emptyResponse );
768
769 String namespaces = declareXPathNamespaces( xmlObject );
770 if( namespaces != null && namespaces.trim().length() > 0 )
771 string = namespaces + string;
772
773 XmlObject[] path = xmlObject.selectPath( string );
774 for( XmlObject xml : path )
775 {
776 setNodeValue( xml.getDomNode(), actor );
777 }
778
779 return xmlObject.toString();
780 }
781 catch( Exception e )
782 {
783 SoapUI.logError( e );
784 }
785
786 return emptyResponse;
787 }
788
789 public static QName getQName( Node node )
790 {
791 if( node.getNamespaceURI() == null )
792 return new QName( node.getNodeName());
793 else
794 return new QName( node.getNamespaceURI(), node.getLocalName() );
795 }
796
797 public static String removeXPathNamespaceDeclarations( String xpath )
798 {
799 while( xpath.startsWith( "declare namespace" ))
800 {
801 int ix = xpath.indexOf( ';' );
802 if( ix == -1 )
803 break;
804
805 xpath = xpath.substring( ix+1 ).trim();
806 }
807 return xpath;
808 }
809
810 public static String stripWhitespaces( String content )
811 {
812 try
813 {
814 XmlObject xml = XmlObject.Factory.parse( content, new XmlOptions().setLoadStripWhitespace().setLoadStripComments() );
815 content = xml.xmlText();
816 }
817 catch( Exception e )
818 {
819 SoapUI.logError( e );
820 }
821
822 return content;
823 }
824
825 public static NodeList getChildElements( Element elm )
826 {
827 List<Element> list = new ArrayList<Element>();
828
829 NodeList nl = elm.getChildNodes();
830 for( int c = 0; c < nl.getLength(); c++ )
831 {
832 Node item = nl.item( c );
833 if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE )
834 list.add( ( Element ) item );
835 }
836
837 return new ElementNodeList( list );
838 }
839
840 public static NodeList getChildElementsByTagName( Element elm, String name )
841 {
842 List<Element> list = new ArrayList<Element>();
843
844 NodeList nl = elm.getChildNodes();
845 for( int c = 0; c < nl.getLength(); c++ )
846 {
847 Node item = nl.item( c );
848 if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE && name.equals( item.getNodeName()) )
849 list.add( ( Element ) item );
850 }
851
852 return new ElementNodeList( list );
853 }
854
855 public static NodeList getChildElementsByTagNameNS( Element elm, String namespaceUri, String localName )
856 {
857 List<Element> list = new ArrayList<Element>();
858
859 NodeList nl = elm.getChildNodes();
860 for( int c = 0; c < nl.getLength(); c++ )
861 {
862 Node item = nl.item( c );
863 if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE &&
864 localName.equals( item.getLocalName()) && namespaceUri.equals( item.getNamespaceURI()))
865 list.add( ( Element ) item );
866 }
867
868 return new ElementNodeList( list );
869 }
870
871 private final static class ElementNodeList implements NodeList
872 {
873 private final List<Element> list;
874
875 public ElementNodeList( List<Element> list )
876 {
877 this.list = list;
878 }
879
880 public int getLength()
881 {
882 return list.size();
883 }
884
885 public Node item( int index )
886 {
887 return list.get( index );
888 }
889 }
890
891 public static boolean seemsToBeXml( String str )
892 {
893 try
894 {
895 if( StringUtils.isNullOrEmpty( str ))
896 return false;
897
898 return XmlObject.Factory.parse( str ) != null;
899 }
900 catch( Exception e )
901 {
902 return false;
903 }
904 }
905
906 public static String extractNamespaces( String xpath )
907 {
908 String result = xpath;
909 int ix = xpath.lastIndexOf( "declare namespace" );
910 if( ix != -1 )
911 {
912 ix = xpath.indexOf( '\'', ix+1 );
913 if( ix != -1 )
914 {
915 ix = xpath.indexOf( '\'', ix+1 );
916 if( ix != -1 )
917 {
918 ix = xpath.indexOf( ';' );
919 if( ix != -1 )
920 {
921 result = xpath.substring( 0, ix+1 );
922 }
923 }
924 }
925 }
926
927 return result;
928 }
929
930 public static String removeUnneccessaryNamespaces( String xml )
931 {
932 if( StringUtils.isNullOrEmpty( xml ))
933 return xml;
934
935 XmlObject xmlObject = null;
936 XmlCursor cursor = null;
937 try
938 {
939 xmlObject = XmlObject.Factory.parse( xml );
940
941 cursor = xmlObject.newCursor();
942 while( cursor.currentTokenType() != TokenType.START && cursor.currentTokenType() != TokenType.ENDDOC )
943 {
944 cursor.toNextToken();
945 }
946
947 if( cursor.currentTokenType() == TokenType.START )
948 {
949 Map nsMap = new HashMap();
950
951 cursor.getAllNamespaces( nsMap );
952 nsMap.remove( cursor.getDomNode().getPrefix() );
953
954 NamedNodeMap attributes = cursor.getDomNode().getAttributes();
955 for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
956 {
957 nsMap.remove( attributes.item( c ).getPrefix() );
958 }
959
960 if( cursor.toFirstChild() )
961 {
962 while( cursor.getDomNode() != xmlObject.getDomNode() )
963 {
964 attributes = cursor.getDomNode().getAttributes();
965 for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
966 {
967 nsMap.remove( attributes.item( c ).getPrefix() );
968 }
969
970 nsMap.remove( cursor.getDomNode().getPrefix() );
971 cursor.toNextToken();
972 }
973 }
974
975 xml = xmlObject.xmlText( new XmlOptions().setSaveOuter().setSavePrettyPrint()
976 .setSaveImplicitNamespaces( nsMap ) );
977 }
978 }
979 catch( XmlException e )
980 {
981
982 }
983 finally
984 {
985 if( cursor != null )
986 cursor.dispose();
987 }
988
989 return xml;
990 }
991
992 public static String replaceNameInPathOrQuery( String pathOrQuery, String oldName, String newName ) throws Exception
993 {
994 Tokenizer t = new Tokenizer();
995 t.tokenize(pathOrQuery, 0, -1, 1);
996 StringBuffer result = new StringBuffer();
997 int lastIx = 0;
998
999 while( t.currentToken != Token.EOF )
1000 {
1001 if( t.currentToken == Token.NAME && t.currentTokenValue.equals( oldName ))
1002 {
1003 result.append( pathOrQuery.substring( lastIx, t.currentTokenStartOffset ) );
1004 result.append( newName );
1005 lastIx = t.currentTokenStartOffset + t.currentTokenValue.length();
1006 }
1007
1008 t.next();
1009 }
1010
1011 if( lastIx < pathOrQuery.length())
1012 result.append( pathOrQuery.substring( lastIx ) );
1013
1014 System.out.println( "returning " + result.toString() );
1015 return result.toString();
1016 }
1017 }
1018