1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.support;
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.HashMap;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.StringTokenizer;
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
35 import org.apache.log4j.Logger;
36 import org.apache.xmlbeans.XmlCursor;
37 import org.apache.xmlbeans.XmlException;
38 import org.apache.xmlbeans.XmlObject;
39 import org.apache.xmlbeans.XmlOptions;
40 import org.w3c.dom.Attr;
41 import org.w3c.dom.Document;
42 import org.w3c.dom.Element;
43 import org.w3c.dom.NamedNodeMap;
44 import org.w3c.dom.Node;
45 import org.w3c.dom.NodeList;
46 import org.w3c.dom.Text;
47 import org.w3c.dom.traversal.DocumentTraversal;
48 import org.w3c.dom.traversal.NodeFilter;
49 import org.w3c.dom.traversal.TreeWalker;
50 import org.xml.sax.InputSource;
51 import org.xml.sax.SAXException;
52
53 import com.sun.org.apache.xpath.internal.XPathAPI;
54
55 /***
56 * General XML-related utilities
57 */
58
59 public final class XmlUtils
60 {
61 private static DocumentBuilder documentBuilder;
62 private final static Logger log = Logger.getLogger( XmlUtils.class );
63
64 static public Document parse( InputStream in )
65 {
66 try
67 {
68 return ensureDocumentBuilder().parse( in );
69 }
70 catch( Exception e )
71 {
72 log.error( "Error parsing InputStream; " + e.getMessage(), e );
73 }
74
75 return null;
76 }
77
78 static public Document parse( String fileName ) throws IOException
79 {
80 try
81 {
82 return ensureDocumentBuilder().parse( fileName );
83 }
84 catch( SAXException e )
85 {
86 log.error( "Error parsing fileName [" + fileName + "]; " + e.getMessage(), e );
87 }
88
89 return null;
90 }
91
92 static public Document parse( InputSource inputSource ) throws IOException
93 {
94 try
95 {
96 return ensureDocumentBuilder().parse( inputSource );
97 }
98 catch( SAXException e )
99 {
100 log.error( "Error parsing InputSource; " + e.getMessage(), e );
101 }
102
103 return null;
104 }
105
106
107 private static DocumentBuilder ensureDocumentBuilder()
108 {
109 if( documentBuilder == null )
110 {
111 try
112 {
113 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
114 dbf.setNamespaceAware( true );
115 documentBuilder = dbf.newDocumentBuilder();
116 }
117 catch( ParserConfigurationException e )
118 {
119 log.error( "Error creating DocumentBuilder; " + e.getMessage(), e );
120 }
121 }
122
123 return documentBuilder;
124 }
125
126 public static void serializePretty( Document document )
127 {
128 try
129 {
130 serializePretty( document, new OutputStreamWriter( System.out ) );
131 }
132 catch( IOException e )
133 {
134 e.printStackTrace();
135 }
136 }
137
138 public static void serializePretty( Document dom, Writer writer )
139 throws IOException
140 {
141 try
142 {
143 XmlObject xmlObject = XmlObject.Factory
144 .parse(dom.getDocumentElement());
145 serializePretty(xmlObject, writer);
146 }
147 catch (Exception e)
148 {
149 throw new IOException( e.getMessage() );
150 }
151 }
152
153 public static void serializePretty( XmlObject xmlObject, Writer writer )
154 throws IOException
155 {
156 try
157 {
158 XmlOptions options = new XmlOptions();
159 options.setSavePrettyPrint();
160 options.setSavePrettyPrintIndent( 3 );
161 options.setSaveNoXmlDecl();
162 options.setSaveAggressiveNamespaces();
163 xmlObject.save(writer, options);
164 }
165 catch (Exception e)
166 {
167 throw new IOException( e.getMessage() );
168 }
169 }
170
171 public static void serialize( Document dom, Writer writer )
172 throws IOException
173 {
174 try
175 {
176 XmlObject xmlObject = XmlObject.Factory
177 .parse(dom.getDocumentElement());
178 xmlObject.save( writer );
179 }
180 catch (Exception e)
181 {
182 throw new IOException( e.getMessage() );
183 }
184 }
185
186 static public void setElementText( Element elm, String text )
187 {
188 Node node = elm.getFirstChild();
189 if( node == null )
190 {
191 if( text != null)
192 elm.appendChild( elm.getOwnerDocument().createTextNode( text ) );
193 }
194 else if( node.getNodeType() == Node.TEXT_NODE )
195 {
196 if( text == null )
197 node.getParentNode().removeChild( node );
198 else
199 node.setNodeValue( text );
200 }
201 else if( text != null )
202 {
203 Text textNode = node.getOwnerDocument().createTextNode( text );
204 elm.insertBefore( textNode, elm.getFirstChild() );
205 }
206 }
207
208 public static String getChildElementText( Element elm, String name )
209 {
210 Element child = getFirstChildElement( elm, name );
211 return child == null ? null : getElementText( child );
212 }
213
214 public static Element getFirstChildElement( Element elm, String name )
215 {
216 NodeList nl = elm.getChildNodes();
217 for( int c = 0; c < nl.getLength(); c++ )
218 {
219 Node node = nl.item( c );
220 if( node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals( name ) )
221 return (Element) node;
222 }
223
224 return null;
225 }
226
227 static public String getElementText( Element elm )
228 {
229 Node node = elm.getFirstChild();
230 if( node != null && node.getNodeType() == Node.TEXT_NODE )
231 return node.getNodeValue();
232
233 return null;
234 }
235
236 public static String getChildElementText( Element elm, String name, String defaultValue )
237 {
238 String result = getChildElementText( elm, name );
239 return result == null ? defaultValue : result;
240 }
241
242 static public String getNodeValue( Node node )
243 {
244 return node.getNodeType() == Node.ELEMENT_NODE ? getElementText( (Element) node ) : node.getNodeValue();
245 }
246
247 public static Node createNodeFromPath( Element modelElement, String path )
248 {
249 try
250 {
251 Document document = modelElement.getOwnerDocument();
252 StringTokenizer st = new StringTokenizer( path, "/" );
253 while( st.hasMoreTokens() )
254 {
255 String t = st.nextToken();
256
257 if( st.hasMoreTokens() )
258 {
259 if( t.equals( ".." ) )
260 {
261 modelElement = (Element) modelElement.getParentNode();
262 }
263 else
264 {
265 Element elm = getFirstChildElement( modelElement, t );
266 if( elm == null )
267 modelElement = (Element) modelElement.insertBefore(
268 document.createElement( t ),
269 getFirstChildElement( modelElement, t ) );
270 else
271 modelElement = elm;
272 }
273 }
274 else
275 {
276 modelElement = (Element) modelElement.insertBefore(
277 document.createElement( t ),
278 getFirstChildElement( modelElement, t ) );
279 }
280 }
281
282 return modelElement;
283 }
284 catch( Exception e )
285 {
286
287 }
288
289 return null;
290 }
291
292 public static Element addChildElement( Element element, String name, String text )
293 {
294 Document document = element.getOwnerDocument();
295 Element result = (Element) element.appendChild( document.createElement( name ) );
296 if( text != null )
297 result.appendChild( document.createTextNode( text ) );
298
299 return result;
300 }
301
302 public static void setChildElementText( Element element, String name, String text )
303 {
304 Element elm = getFirstChildElement( element, name );
305 if( elm == null )
306 {
307 elm = element.getOwnerDocument().createElement( name );
308 element.appendChild( elm );
309 }
310
311 setElementText( elm, text );
312 }
313
314 public static Document parseXml( String xmlString ) throws IOException
315 {
316 return parse( new InputSource( new StringReader( xmlString )));
317 }
318
319 public static void dumpParserErrors(XmlObject xmlObject)
320 {
321 List errors = new ArrayList();
322 xmlObject.validate(new XmlOptions().setErrorListener(errors));
323 for (Iterator i = errors.iterator(); i.hasNext();)
324 {
325 System.out.println(i.next());
326 }
327 }
328
329 public static String transferValues(String source, String dest)
330 {
331 try
332 {
333 Document sourceDom = parseXml(source);
334 Document destDom = parseXml(dest);
335
336 TreeWalker walker = ((DocumentTraversal)sourceDom).createTreeWalker( sourceDom.getDocumentElement(),
337 NodeFilter.SHOW_ELEMENT, null, true );
338
339 Element elm = (Element) walker.nextNode();
340 while( elm != null )
341 {
342 String path = getElementPath( elm );
343 Node nsNode = getNSNode( elm );
344 Element elm2 = (Element) XPathAPI.selectSingleNode( destDom.getDocumentElement(), path, nsNode );
345 if( elm2 != null )
346 {
347
348 NamedNodeMap attributes = elm.getAttributes();
349 for( int c = 0; c < attributes.getLength(); c++ )
350 {
351 Attr attr = (Attr) attributes.item( c );
352 elm2.setAttribute( attr.getNodeName(), attr.getNodeValue() );
353 }
354
355
356 setElementText( elm2, getElementText( elm ));
357 }
358
359 elm = (Element) walker.nextNode();
360 }
361
362 StringWriter writer = new StringWriter();
363 serialize( destDom, writer );
364 return writer.toString();
365 }
366 catch (Exception e)
367 {
368 e.printStackTrace();
369 }
370
371 return dest;
372 }
373
374 private static Node getNSNode(Node elm)
375 {
376 Element result = elm.getOwnerDocument().createElement("nsnode");
377
378 while( elm != null )
379 {
380 NamedNodeMap attributes = elm.getAttributes();
381 if( attributes != null )
382 {
383 for( int c = 0; c < attributes.getLength(); c++ )
384 {
385 Node attr = attributes.item( c );
386 if( attr.getNodeName().startsWith( "xmlns:" ) || attr.getNodeName().equals( "xmlns") )
387 {
388 result.setAttribute( attr.getNodeName(), attr.getNodeValue() );
389 }
390 }
391 }
392
393 elm = elm.getParentNode();
394 }
395
396 return result;
397 }
398
399 /***
400 * Returns absolute xpath for specified element, ignores namespaces
401 *
402 * @param elm the element to create for
403 * @return the elements path in its containing document
404 */
405
406 public static String getElementPath(Element element)
407 {
408 Node elm = element;
409
410 String result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]";
411 while( elm.getParentNode() != null && elm.getParentNode().getNodeType() != Node.DOCUMENT_NODE )
412 {
413 elm = elm.getParentNode();
414 result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]/" + result;
415 }
416
417 return "/" + result;
418 }
419
420 /***
421 * Gets the index of the specified element amongst elements with the same name
422 *
423 * @param element the element to get for
424 * @return the index of the element, will be >= 1
425 */
426
427 public static int getElementIndex(Node element)
428 {
429 int result = 1;
430
431 Node elm = element.getPreviousSibling();
432 while( elm != null )
433 {
434 if( elm.getNodeType() == Node.ELEMENT_NODE && elm.getNodeName().equals( element.getNodeName() ))
435 result++;
436 elm = elm.getPreviousSibling();
437 }
438
439 return result;
440 }
441
442 public static String declareXPathNamespaces( String xmlString ) throws XmlException
443 {
444 XmlObject xml = XmlObject.Factory.parse(xmlString);
445 Map<QName,String> map = new HashMap<QName,String>();
446 XmlCursor cursor = xml.newCursor();
447
448 while( cursor.hasNextToken() )
449 {
450 if( cursor.toNextToken().isNamespace() )
451 map.put( cursor.getName(), cursor.getTextValue() );
452 }
453
454 Iterator<QName> i = map.keySet().iterator();
455 int nsCnt = 0;
456
457 StringBuffer buf = new StringBuffer();
458 Set<String> prefixes = new HashSet<String>();
459 Set<String> usedPrefixes = new HashSet<String>();
460
461 while( i.hasNext() )
462 {
463 QName name = i.next();
464 String prefix = name.getLocalPart();
465 if( prefix.length() == 0 ) prefix = "ns" + (++nsCnt);
466 else if( prefix.equals( "xsd") || prefix.equals( "xsi")) continue;
467
468 if( prefixes.contains( prefix ))
469 {
470 int c = 1;
471 while( usedPrefixes.contains( prefix + c )) c++;
472
473 prefix = prefix + c;
474 }
475 else prefixes.add( prefix );
476
477 buf.append( "declare namespace " );
478 buf.append( prefix );
479 buf.append( "='" );
480 buf.append( map.get( name ));
481 buf.append( "';\n");
482
483 usedPrefixes.add( prefix );
484 }
485
486 return buf.toString();
487
488 }
489 }
490