/*
* soapUI, copyright (C) 2004-2011 eviware.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details at gnu.org.
*/
package com.eviware.soapui.support.xml;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import net.sf.saxon.expr.Token;
import net.sf.saxon.expr.Tokenizer;
import org.apache.log4j.Logger;
import org.apache.xerces.util.SecurityManager;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.XmlAnySimpleType;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlCursor.TokenType;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.support.Constants;
import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.types.StringToStringMap;
/**
* General XML-related utilities
*/
@SuppressWarnings( "deprecation" )
public final class XmlUtils
{
private static DocumentBuilder documentBuilder;
private final static Logger log = Logger.getLogger( XmlUtils.class );
static synchronized public Document parse( InputStream in )
{
try
{
return ensureDocumentBuilder().parse( in );
}
catch( Exception e )
{
log.error( "Error parsing InputStream; " + e.getMessage(), e );
}
return null;
}
static synchronized public Document parse( String fileName ) throws IOException
{
try
{
return ensureDocumentBuilder().parse( fileName );
}
catch( SAXException e )
{
log.error( "Error parsing fileName [" + fileName + "]; " + e.getMessage(), e );
}
return null;
}
public static String entitize( String xml )
{
return xml.replaceAll( "&", "&" ).replaceAll( "<", "<" ).replaceAll( ">", ">" )
.replaceAll( "\"", """ ).replaceAll( "'", "'" );
}
public static String entitizeContent( String xml )
{
return xml.replaceAll( "&", "&" ).replaceAll( "\"", """ ).replaceAll( "'", "'" );
}
static synchronized public Document parse( InputSource inputSource ) throws IOException
{
try
{
return ensureDocumentBuilder().parse( inputSource );
}
catch( SAXException e )
{
throw new IOException( e.toString() );
}
}
private static DocumentBuilder ensureDocumentBuilder()
{
if( documentBuilder == null )
{
try
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware( true );
documentBuilder = dbf.newDocumentBuilder();
}
catch( ParserConfigurationException e )
{
log.error( "Error creating DocumentBuilder; " + e.getMessage() );
}
}
return documentBuilder;
}
public static String serializePretty( Document document )
{
try
{
Writer out = new StringWriter();
serializePretty( document, out );
return out.toString();
}
catch( IOException e )
{
log.error( "Failed to serialize: " + e );
}
return null;
}
public static void serializePretty( Document dom, Writer writer ) throws IOException
{
try
{
XmlObject xmlObject = XmlObject.Factory.parse( dom.getDocumentElement() );
serializePretty( xmlObject, writer );
}
catch( Exception e )
{
throw new IOException( e.toString() );
}
}
public static void serializePretty( XmlObject xmlObject, Writer writer ) throws IOException
{
XmlOptions options = new XmlOptions();
options.setSavePrettyPrint();
options.setSavePrettyPrintIndent( 3 );
options.setSaveNoXmlDecl();
options.setSaveAggressiveNamespaces();
// StringToStringMap map = new StringToStringMap();
// map.put( SoapVersion.Soap11.getEnvelopeNamespace(), "SOAPENV" );
// map.put( SoapVersion.Soap12.getEnvelopeNamespace(), "SOAPENV" );
//
// options.setSaveSuggestedPrefixes( map );
xmlObject.save( writer, options );
}
public static XmlObject createXmlObject( InputStream input, XmlOptions xmlOptions ) throws XmlException
{
try
{
return XmlObject.Factory.parse( input, xmlOptions );
}
catch( Exception e )
{
throw new XmlException( e.toString() );
}
}
public static XmlObject createXmlObject( String input, XmlOptions xmlOptions ) throws XmlException
{
return XmlObject.Factory.parse( input, xmlOptions );
}
public static XmlObject createXmlObject( URL input, XmlOptions xmlOptions ) throws XmlException
{
try
{
return XmlObject.Factory.parse( input, xmlOptions );
}
catch( Exception e )
{
throw new XmlException( e.toString() );
}
}
public static XmlObject createXmlObject( Node input, XmlOptions xmlOptions ) throws XmlException
{
return XmlObject.Factory.parse( input, xmlOptions );
}
public static XmlObject createXmlObject( File input, XmlOptions xmlOptions ) throws XmlException
{
try
{
return XmlObject.Factory.parse( input, xmlOptions );
}
catch( Exception e )
{
throw new XmlException( e.toString() );
}
}
public static XmlObject createXmlObject( InputStream input ) throws XmlException
{
try
{
return XmlObject.Factory.parse( input );
}
catch( Exception e )
{
throw new XmlException( e.toString() );
}
}
public static XmlObject createXmlObject( String input ) throws XmlException
{
return XmlObject.Factory.parse( input );
}
public static XmlObject createXmlObject( URL input ) throws XmlException
{
try
{
return XmlObject.Factory.parse( input );
}
catch( Exception e )
{
throw new XmlException( e.toString() );
}
}
public static XmlObject createXmlObject( Node input ) throws XmlException
{
return XmlObject.Factory.parse( input );
}
public static XmlObject createXmlObject( File input ) throws XmlException
{
try
{
return XmlObject.Factory.parse( input );
}
catch( Exception e )
{
throw new XmlException( e.toString() );
}
}
/**
* XmlOptions configuration used in preventing XML Bomb
*
* @return XmlOptions
*/
public static XmlOptions createDefaultXmlOptions()
{
XmlOptions xmlOptions;
try
{
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
SecurityManager securityManager = new SecurityManager();
// Default seems to be 64000!
securityManager.setEntityExpansionLimit( 16 );
saxParser.setProperty( "http://apache.org/xml/properties/security-manager", securityManager );
XMLReader xmlReader = saxParser.getXMLReader();
xmlOptions = new XmlOptions().setLoadUseXMLReader( xmlReader );
}
catch( Exception e )
{
xmlOptions = new XmlOptions();
log.error( "Error creating XmlOptions; " + e.getMessage(), e );
}
return xmlOptions;
}
public static void serialize( Document dom, Writer writer ) throws IOException
{
serialize( dom.getDocumentElement(), writer );
}
public static void serialize( Element elm, Writer writer ) throws IOException
{
try
{
XmlObject xmlObject = XmlObject.Factory.parse( elm );
xmlObject.save( writer );
}
catch( XmlException e )
{
throw new IOException( e.toString() );
}
}
static public String serialize( Node node, boolean prettyPrint )
{
try
{
XmlObject xmlObject = XmlObject.Factory.parse( node );
return prettyPrint ? xmlObject.xmlText( new XmlOptions().setSavePrettyPrint() ) : xmlObject.xmlText();
}
catch( XmlException e )
{
return e.toString();
}
}
static public void setElementText( Element elm, String text )
{
Node node = elm.getFirstChild();
if( node == null )
{
if( text != null )
elm.appendChild( elm.getOwnerDocument().createTextNode( text ) );
}
else if( node.getNodeType() == Node.TEXT_NODE )
{
if( text == null )
node.getParentNode().removeChild( node );
else
node.setNodeValue( text );
}
else if( text != null )
{
Text textNode = node.getOwnerDocument().createTextNode( text );
elm.insertBefore( textNode, elm.getFirstChild() );
}
}
public static String getChildElementText( Element elm, String name )
{
Element child = getFirstChildElement( elm, name );
return child == null ? null : getElementText( child );
}
public static Element getFirstChildElement( Element elm )
{
return getFirstChildElement( elm, null );
}
public static Element getFirstChildElement( Element elm, String name )
{
if( elm == null )
return null;
NodeList nl = elm.getChildNodes();
for( int c = 0; c < nl.getLength(); c++ )
{
Node node = nl.item( c );
if( node.getNodeType() == Node.ELEMENT_NODE && ( name == null || node.getNodeName().equals( name ) ) )
return ( Element )node;
}
return null;
}
public static Element getFirstChildElementIgnoreCase( Element elm, String name )
{
if( elm == null )
return null;
NodeList nl = elm.getChildNodes();
for( int c = 0; c < nl.getLength(); c++ )
{
Node node = nl.item( c );
if( node.getNodeType() == Node.ELEMENT_NODE && ( name == null || node.getNodeName().equalsIgnoreCase( name ) ) )
return ( Element )node;
}
return null;
}
public static Element getFirstChildElementNS( Element elm, String tns, String localName )
{
if( tns == null && localName == null )
return getFirstChildElement( elm );
if( tns == null || tns.length() == 0 )
return getFirstChildElement( elm, localName );
NodeList nl = elm.getChildNodes();
for( int c = 0; c < nl.getLength(); c++ )
{
Node node = nl.item( c );
if( node.getNodeType() != Node.ELEMENT_NODE )
continue;
if( localName == null && tns.equals( node.getNamespaceURI() ) )
return ( Element )node;
if( localName != null && tns.equals( node.getNamespaceURI() ) && localName.equals( node.getLocalName() ) )
return ( Element )node;
}
return null;
}
static public String getElementText( Element elm )
{
Node node = elm.getFirstChild();
if( node != null && node.getNodeType() == Node.TEXT_NODE )
return node.getNodeValue();
return null;
}
static public String getFragmentText( DocumentFragment elm )
{
Node node = elm.getFirstChild();
if( node != null && node.getNodeType() == Node.TEXT_NODE )
return node.getNodeValue();
return null;
}
public static String getChildElementText( Element elm, String name, String defaultValue )
{
String result = getChildElementText( elm, name );
return result == null ? defaultValue : result;
}
static public String getNodeValue( Node node )
{
if( node == null )
return null;
if( node.getNodeType() == Node.ELEMENT_NODE )
return getElementText( ( Element )node );
else if( node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE )
return getFragmentText( ( DocumentFragment )node );
else
return node.getNodeValue();
}
public static Node createNodeFromPath( Element modelElement, String path )
{
Document document = modelElement.getOwnerDocument();
StringTokenizer st = new StringTokenizer( path, "/" );
while( st.hasMoreTokens() )
{
String t = st.nextToken();
if( st.hasMoreTokens() )
{
if( t.equals( ".." ) )
{
modelElement = ( Element )modelElement.getParentNode();
}
else
{
Element elm = getFirstChildElement( modelElement, t );
if( elm == null )
modelElement = ( Element )modelElement.insertBefore( document.createElement( t ),
getFirstChildElement( modelElement, t ) );
else
modelElement = elm;
}
}
else
{
modelElement = ( Element )modelElement.insertBefore( document.createElement( t ),
getFirstChildElement( modelElement, t ) );
}
}
return modelElement;
}
public static Element addChildElement( Element element, String name, String text )
{
Document document = element.getOwnerDocument();
Element result = ( Element )element.appendChild( document.createElement( name ) );
if( text != null )
result.appendChild( document.createTextNode( text ) );
return result;
}
public static void setChildElementText( Element element, String name, String text )
{
Element elm = getFirstChildElement( element, name );
if( elm == null )
{
elm = element.getOwnerDocument().createElement( name );
element.appendChild( elm );
}
setElementText( elm, text );
}
public static Document parseXml( String xmlString ) throws IOException
{
return parse( new InputSource( new StringReader( xmlString ) ) );
}
public static void dumpParserErrors( XmlObject xmlObject )
{
List<?> errors = new ArrayList<Object>();
xmlObject.validate( new XmlOptions().setErrorListener( errors ) );
for( Iterator<?> i = errors.iterator(); i.hasNext(); )
{
System.out.println( i.next() );
}
}
public static String transferValues( String source, String dest )
{
if( StringUtils.isNullOrEmpty( source ) || StringUtils.isNullOrEmpty( dest ) )
return dest;
XmlCursor cursor = null;
try
{
XmlObject sourceXml = XmlObject.Factory.parse( source );
XmlObject destXml = XmlObject.Factory.parse( dest );
cursor = sourceXml.newCursor();
cursor.toNextToken();
while( !cursor.isEnddoc() )
{
while( !cursor.isContainer() && !cursor.isEnddoc() )
cursor.toNextToken();
if( cursor.isContainer() )
{
Element elm = ( Element )cursor.getDomNode();
String path = createXPath( elm );
XmlObject[] paths = destXml.selectPath( path );
if( paths != null && paths.length > 0 )
{
Element elm2 = ( Element )paths[0].getDomNode();
// transfer attributes
transferAttributes( elm, elm2 );
// transfer text
setElementText( elm2, getElementText( elm ) );
while( elm.getNextSibling() != null && elm2.getNextSibling() != null
&& elm.getNextSibling().getNodeName().equals( elm.getNodeName() )
&& !elm2.getNextSibling().getNodeName().equals( elm2.getNodeName() ) )
{
elm2 = ( Element )elm2.getParentNode().insertBefore(
elm2.getOwnerDocument().createElementNS( elm2.getNamespaceURI(), elm2.getLocalName() ),
elm2.getNextSibling() );
elm = ( Element )elm.getNextSibling();
// transfer attributes
transferAttributes( elm, elm2 );
// transfer text
setElementText( elm2, getElementText( elm ) );
}
}
cursor.toNextToken();
}
}
return destXml.xmlText();
}
catch( Exception e )
{
SoapUI.logError( e );
}
finally
{
if( cursor != null )
cursor.dispose();
}
return dest;
}
private static void transferAttributes( Element elm, Element elm2 )
{
NamedNodeMap attributes = elm.getAttributes();
for( int c = 0; c < attributes.getLength(); c++ )
{
Attr attr = ( Attr )attributes.item( c );
elm2.setAttributeNodeNS( ( Attr )elm2.getOwnerDocument().importNode( attr, true ) );
}
}
/**
* Returns absolute xpath for specified element, ignores namespaces
*
* @param element
* the element to create for
* @return the elements path in its containing document
*/
public static String getElementPath( Element element )
{
Node elm = element;
String result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]";
while( elm.getParentNode() != null && elm.getParentNode().getNodeType() != Node.DOCUMENT_NODE )
{
elm = elm.getParentNode();
result = elm.getNodeName() + "[" + getElementIndex( elm ) + "]/" + result;
}
return "/" + result;
}
/**
* Gets the index of the specified element amongst elements with the same
* name
*
* @param element
* the element to get for
* @return the index of the element, will be >= 1
*/
public static int getElementIndex( Node element )
{
int result = 1;
Node elm = element.getPreviousSibling();
while( elm != null )
{
if( elm.getNodeType() == Node.ELEMENT_NODE && elm.getNodeName().equals( element.getNodeName() ) )
result++ ;
elm = elm.getPreviousSibling();
}
return result;
}
public static String declareXPathNamespaces( String xmlString ) throws XmlException
{
return declareXPathNamespaces( XmlObject.Factory.parse( xmlString ) );
}
public static synchronized String prettyPrintXml( String xml )
{
try
{
if( !XmlUtils.seemsToBeXml( xml ) )
return xml;
StringWriter writer = new StringWriter();
XmlUtils.serializePretty( XmlObject.Factory.parse( xml ), writer );
return writer.toString();
}
catch( Exception e )
{
log.warn( "Failed to prettyPrint xml [" + xml + "]: " + e );
return xml;
}
}
public static synchronized String prettyPrintXml( XmlObject xml )
{
try
{
if( xml == null )
return null;
StringWriter writer = new StringWriter();
XmlUtils.serializePretty( xml, writer );
return writer.toString();
}
catch( Exception e )
{
log.warn( "Failed to prettyPrint xml [" + xml + "]: " + e );
return xml.xmlText();
}
}
public static String declareXPathNamespaces( WsdlInterface iface )
{
StringBuffer buf = new StringBuffer();
buf.append( "declare namespace soap='" );
buf.append( iface.getSoapVersion().getEnvelopeNamespace() );
buf.append( "';\n" );
try
{
Collection<String> namespaces = iface.getWsdlContext().getInterfaceDefinition().getDefinedNamespaces();
int c = 1;
for( Iterator<String> i = namespaces.iterator(); i.hasNext(); )
{
buf.append( "declare namespace ns" );
buf.append( c++ );
buf.append( "='" );
buf.append( i.next() );
buf.append( "';\n" );
}
}
catch( Exception e )
{
SoapUI.logError( e );
}
return buf.toString();
}
public static String createXPath( Node node )
{
return createXPath( node, false, false, false, null );
}
public static String createAbsoluteXPath( Node node )
{
return createXPath( node, false, false, true, null );
}
public static String createXPath( Node node, boolean anonymous, boolean selectText, XPathModifier modifier )
{
return createXPath( node, anonymous, selectText, false, modifier );
}
public static String createXPath( Node node, boolean anonymous, boolean selectText, boolean absolute,
XPathModifier modifier )
{
XPathData xpathData = createXPathData( node, anonymous, selectText, absolute );
if( xpathData == null )
return null;
return xpathData.buildXPath( modifier );
}
public static XPathData createXPathData( Node node, boolean anonymous, boolean selectText, boolean absolute )
{
StringToStringMap nsMap = new StringToStringMap();
List<String> pathComponents = new ArrayList<String>();
int nsCnt = 1;
String namespaceURI = node.getNamespaceURI();
// if( node.getNodeType() == Node.TEXT_NODE )
// {
// node = node.getParentNode();
// }
if( node.getNodeType() == Node.ATTRIBUTE_NODE )
{
if( namespaceURI != null && namespaceURI.length() > 0 )
{
String prefix = node.getPrefix();
if( prefix == null || prefix.length() == 0 )
prefix = "ns" + nsCnt++ ;
nsMap.put( namespaceURI, prefix );
pathComponents.add( "@" + prefix + ":" + node.getLocalName() );
}
else
{
pathComponents.add( "@" + node.getLocalName() );
}
node = ( ( Attr )node ).getOwnerElement();
}
else if( node.getNodeType() == Node.DOCUMENT_NODE )
{
node = ( ( Document )node ).getDocumentElement();
}
// else if( node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE )
// {
// node =
// ((DocumentFragment)node).getOwnerDocument().getDocumentElement();
// }
if( node.getNodeType() == Node.ELEMENT_NODE )
{
int index = anonymous ? 0 : findNodeIndex( node );
String pc = null;
namespaceURI = node.getNamespaceURI();
if( namespaceURI != null && namespaceURI.length() > 0 )
{
String prefix = node.getPrefix();
if( prefix == null || prefix.length() == 0 )
prefix = "ns" + nsCnt++ ;
while( !nsMap.containsKey( namespaceURI ) && nsMap.containsValue( prefix ) )
{
prefix = "ns" + nsCnt++ ;
}
nsMap.put( namespaceURI, prefix );
pc = prefix + ":" + node.getLocalName();
}
else
{
pc = node.getLocalName();
}
String elementText = XmlUtils.getElementText( ( Element )node );
// not an attribute?
if( selectText && pathComponents.isEmpty() && elementText != null && elementText.trim().length() > 0 )
pathComponents.add( "text()" );
pathComponents.add( pc + ( ( index == 0 ) ? "" : "[" + index + "]" ) );
}
else
return null;
node = node.getParentNode();
namespaceURI = node.getNamespaceURI();
while( node != null
&& node.getNodeType() == Node.ELEMENT_NODE
&& ( absolute || ( !"Body".equals( node.getNodeName() )
&& !SoapVersion.Soap11.getEnvelopeNamespace().equals( namespaceURI ) && !SoapVersion.Soap12
.getEnvelopeNamespace().equals( namespaceURI ) ) ) )
{
int index = anonymous ? 0 : findNodeIndex( node );
String ns = nsMap.get( namespaceURI );
String pc = null;
if( ns == null && namespaceURI != null && namespaceURI.length() > 0 )
{
String prefix = node.getPrefix();
if( prefix == null || prefix.length() == 0 )
prefix = "ns" + nsCnt++ ;
while( !nsMap.containsKey( namespaceURI ) && nsMap.containsValue( prefix ) )
{
prefix = "ns" + nsCnt++ ;
}
nsMap.put( namespaceURI, prefix );
ns = nsMap.get( namespaceURI );
pc = prefix + ":" + node.getLocalName();
}
else if( ns != null )
{
pc = ns + ":" + node.getLocalName();
}
else
{
pc = node.getLocalName();
}
pathComponents.add( pc + ( ( index == 0 ) ? "" : "[" + index + "]" ) );
node = node.getParentNode();
namespaceURI = node.getNamespaceURI();
}
return new XPathData( nsMap, pathComponents, absolute );
}
private static int findNodeIndex( Node node )
{
String nm = node.getLocalName();
String ns = node.getNamespaceURI();
short nt = node.getNodeType();
Node parentNode = node.getParentNode();
if( parentNode.getNodeType() != Node.ELEMENT_NODE )
return 1;
Node child = parentNode.getFirstChild();
int ix = 0;
while( child != null )
{
if( child == node )
return ix + 1;
if( child.getNodeType() == nt
&& nm.equals( child.getLocalName() )
&& ( ( ns == null && child.getNamespaceURI() == null ) || ( ns != null && ns.equals( child
.getNamespaceURI() ) ) ) )
ix++ ;
child = child.getNextSibling();
}
throw new RuntimeException( "Child node not found in parent!?" );
}
public static boolean setNodeValue( Node domNode, String string )
{
if( domNode == null )
return false;
short nodeType = domNode.getNodeType();
switch( nodeType )
{
case Node.ELEMENT_NODE :
{
setElementText( ( Element )domNode, string );
break;
}
case Node.ATTRIBUTE_NODE :
case Node.TEXT_NODE :
{
domNode.setNodeValue( string );
break;
}
case Node.PROCESSING_INSTRUCTION_NODE :
{
( ( ProcessingInstruction )domNode ).setData( string );
break;
}
case Node.CDATA_SECTION_NODE :
{
( ( CDATASection )domNode ).setData( string );
break;
}
default :
{
return false;
}
}
return true;
}
public static String declareXPathNamespaces( XmlObject xmlObject )
{
Map<QName, String> map = new HashMap<QName, String>();
XmlCursor cursor = xmlObject.newCursor();
while( cursor.hasNextToken() )
{
if( cursor.toNextToken().isNamespace() )
map.put( cursor.getName(), cursor.getTextValue() );
}
cursor.dispose();
Iterator<QName> i = map.keySet().iterator();
int nsCnt = 0;
StringBuffer buf = new StringBuffer();
Set<String> prefixes = new HashSet<String>();
Set<String> usedPrefixes = new HashSet<String>();
while( i.hasNext() )
{
QName name = i.next();
String prefix = name.getLocalPart();
if( prefix.length() == 0 )
prefix = "ns" + Integer.toString( ++nsCnt );
else if( prefix.equals( "xsd" ) || prefix.equals( "xsi" ) )
continue;
if( usedPrefixes.contains( prefix ) )
{
int c = 1;
while( usedPrefixes.contains( prefix + c ) )
c++ ;
prefix = prefix + Integer.toString( c );
}
else
prefixes.add( prefix );
buf.append( "declare namespace " );
buf.append( prefix );
buf.append( "='" );
buf.append( map.get( name ) );
buf.append( "';\n" );
usedPrefixes.add( prefix );
}
return buf.toString();
}
public static String setXPathContent( String xmlText, String xpath, String value )
{
try
{
XmlObject xmlObject = XmlObject.Factory.parse( xmlText );
String namespaces = declareXPathNamespaces( xmlObject );
if( namespaces != null && namespaces.trim().length() > 0 )
xpath = namespaces + xpath;
XmlObject[] path = xmlObject.selectPath( xpath );
for( XmlObject xml : path )
{
setNodeValue( xml.getDomNode(), value );
}
return xmlObject.toString();
}
catch( Exception e )
{
SoapUI.logError( e );
}
return xmlText;
}
public static QName getQName( Node node )
{
if( node == null )
return null;
else if( node.getNamespaceURI() == null )
return new QName( node.getNodeName() );
else
return new QName( node.getNamespaceURI(), node.getLocalName() );
}
public static String removeXPathNamespaceDeclarations( String xpath )
{
while( xpath.startsWith( "declare namespace" ) )
{
int ix = xpath.indexOf( ';' );
if( ix == -1 )
break;
xpath = xpath.substring( ix + 1 ).trim();
}
return xpath;
}
public static String stripWhitespaces( String content )
{
try
{
XmlObject xml = XmlObject.Factory.parse( content, new XmlOptions().setLoadStripWhitespace()
.setLoadStripComments() );
content = xml.xmlText();
}
catch( Exception e )
{
SoapUI.logError( e );
}
return content;
}
public static NodeList getChildElements( Element elm )
{
List<Element> list = new ArrayList<Element>();
NodeList nl = elm.getChildNodes();
for( int c = 0; c < nl.getLength(); c++ )
{
Node item = nl.item( c );
if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE )
list.add( ( Element )item );
}
return new ElementNodeList( list );
}
public static NodeList getChildElementsByTagName( Element elm, String name )
{
List<Element> list = new ArrayList<Element>();
NodeList nl = elm.getChildNodes();
for( int c = 0; c < nl.getLength(); c++ )
{
Node item = nl.item( c );
if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE && name.equals( item.getNodeName() ) )
list.add( ( Element )item );
}
return new ElementNodeList( list );
}
public static NodeList getChildElementsOfType( Element elm, SchemaType schemaType )
{
List<Element> list = new ArrayList<Element>();
NodeList nl = elm.getChildNodes();
for( int c = 0; c < nl.getLength(); c++ )
{
Node item = nl.item( c );
if( item.getParentNode() == elm
&& item.getNodeType() == Node.ELEMENT_NODE
&& ( ( Element )item ).getAttributeNS( Constants.XSI_NS, "type" ).endsWith(
":" + schemaType.getName().getLocalPart() ) )
{
list.add( ( Element )item );
}
}
return new ElementNodeList( list );
}
public static NodeList getChildElementsNS( Element elm, QName name )
{
return getChildElementsByTagNameNS( elm, name.getNamespaceURI(), name.getLocalPart() );
}
public static NodeList getChildElementsByTagNameNS( Element elm, String namespaceUri, String localName )
{
List<Element> list = new ArrayList<Element>();
NodeList nl = elm.getChildNodes();
for( int c = 0; c < nl.getLength(); c++ )
{
Node item = nl.item( c );
if( item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE
&& localName.equals( item.getLocalName() ) && namespaceUri.equals( item.getNamespaceURI() ) )
list.add( ( Element )item );
}
return new ElementNodeList( list );
}
public static String serialize( Document document )
{
StringWriter writer = new StringWriter();
try
{
serialize( document, writer );
}
catch( IOException e )
{
e.printStackTrace();
}
return writer.toString();
}
public static Element getFirstChildElementNS( Element domNode, QName name )
{
return getFirstChildElementNS( domNode, name.getNamespaceURI(), name.getLocalPart() );
}
public static QName findTypeNameForXsiType( String typeName, Element elm )
{
int ix = typeName.indexOf( ':' );
if( ix == -1 )
return null;
String prefix = typeName.substring( 0, ix );
String localName = typeName.substring( ix + 1 );
String namespaceUri = elm.getAttribute( "xmlns:" + prefix );
if( !StringUtils.hasContent( namespaceUri ) )
namespaceUri = findNamespaceForPrefix( elm, prefix );
if( StringUtils.hasContent( namespaceUri ) )
{
return new QName( namespaceUri, localName );
}
return null;
}
private static String findNamespaceForPrefix( Element elm, String prefix )
{
String namespaceUri = null;
while( StringUtils.isNullOrEmpty( namespaceUri ) && elm != null )
{
if( elm.getParentNode().getNodeType() != Node.ELEMENT_NODE )
break;
elm = ( Element )elm.getParentNode();
namespaceUri = elm.getAttribute( "xmlns:" + prefix );
}
return StringUtils.isNullOrEmpty( namespaceUri ) ? null : namespaceUri;
}
public static String findPrefixForNamespace( Element elm, String namespace )
{
while( elm != null )
{
NamedNodeMap attributes = elm.getAttributes();
for( int c = 0; c < attributes.getLength(); c++ )
{
if( attributes.item( c ).getNodeValue().equals( namespace )
&& attributes.item( c ).getNodeName().startsWith( "xmlns:" ) )
{
return attributes.item( c ).getNodeName().substring( 6 );
}
}
if( elm.getParentNode().getNodeType() != Node.ELEMENT_NODE )
break;
elm = ( Element )elm.getParentNode();
}
return null;
}
public static void setXsiType( Element elm, QName name )
{
String prefix = findPrefixForNamespace( elm, name.getNamespaceURI() );
if( prefix == null )
{
prefix = generatePrefixForNamespace( name.getNamespaceURI() );
while( findNamespaceForPrefix( elm, prefix ) != null )
{
prefix = generatePrefixForNamespace( name.getNamespaceURI() );
}
elm.setAttribute( "xmlns:" + prefix, name.getNamespaceURI() );
}
elm.setAttributeNS( Constants.XSI_NS, "type", prefix + ":" + name.getLocalPart() );
}
private static String generatePrefixForNamespace( String namespaceURI )
{
return "ns" + ( int )( Math.random() * 1000 );
}
public static QName createQName( Node node )
{
return new QName( node.getNamespaceURI(), node.getLocalName() );
}
public static Node getNextElementSibling( Node node )
{
node = node.getNextSibling();
while( node != null && node.getNodeType() != Node.ELEMENT_NODE )
{
node = node.getNextSibling();
}
return node;
}
public static Document createDocument( QName element )
{
ensureDocumentBuilder();
Document document = documentBuilder.newDocument();
document.appendChild( document.createElementNS( element.getNamespaceURI(), element.getLocalPart() ) );
return document;
}
public static String getValueForMatch( XmlCursor cursor )
{
Node domNode = cursor.getDomNode();
String stringValue;
if( domNode.getNodeType() == Node.ATTRIBUTE_NODE || domNode.getNodeType() == Node.TEXT_NODE )
{
stringValue = domNode.getNodeValue();
}
else if( cursor.getObject() instanceof XmlAnySimpleType )
{
stringValue = ( ( XmlAnySimpleType )cursor.getObject() ).getStringValue();
}
else
{
if( domNode.getNodeType() == Node.ELEMENT_NODE )
{
Element elm = ( Element )domNode;
if( elm.getChildNodes().getLength() == 1 && !hasContentAttributes( elm ) )
{
stringValue = getElementText( elm );
}
else
{
stringValue = cursor.getObject().xmlText(
new XmlOptions().setSavePrettyPrint().setSaveOuter().setSaveAggressiveNamespaces() );
}
}
else
{
stringValue = domNode.getNodeValue();
}
}
return stringValue;
}
public static boolean hasContentAttributes( Element elm )
{
NamedNodeMap attributes = elm.getAttributes();
for( int c = 0; c < attributes.getLength(); c++ )
{
Node item = attributes.item( c );
String ns = item.getNamespaceURI();
if( !ns.equals( Constants.XML_NS )
// && !ns.equals( Constants.XSI_NS ) && !ns.equals(
// Constants.XSI_NS_2000 )
// && !ns.equals( Constants.XSD_NS )
)
return true;
}
return false;
}
public static String getValueForMatch( Node domNode, boolean prettyPrintXml )
{
String stringValue;
if( domNode.getNodeType() == Node.ATTRIBUTE_NODE || domNode.getNodeType() == Node.TEXT_NODE )
{
stringValue = domNode.getNodeValue();
}
else
{
if( domNode.getNodeType() == Node.ELEMENT_NODE )
{
Element elm = ( Element )domNode;
if( elm.getChildNodes().getLength() == 1 && !hasContentAttributes( elm ) )
{
stringValue = getElementText( elm );
}
else
{
stringValue = XmlUtils.serialize( domNode, prettyPrintXml );
}
}
else
{
stringValue = domNode.getNodeValue();
}
}
return stringValue;
}
public static String selectFirstNodeValue( XmlObject xmlObject, String xpath ) throws XmlException
{
Node domNode = selectFirstDomNode( xmlObject, xpath );
return domNode == null ? null : getNodeValue( domNode );
}
public static String[] selectNodeValues( XmlObject xmlObject, String xpath )
{
Node[] nodes = selectDomNodes( xmlObject, xpath );
String[] result = new String[nodes.length];
for( int c = 0; c < nodes.length; c++ )
{
result[c] = getNodeValue( nodes[c] );
}
return result;
}
public static Node selectFirstDomNode( XmlObject xmlObject, String xpath )
{
XmlCursor cursor = xmlObject.newCursor();
try
{
cursor.selectPath( xpath );
if( cursor.toNextSelection() )
{
return cursor.getDomNode();
}
else
return null;
}
finally
{
cursor.dispose();
}
}
public static Node[] selectDomNodes( XmlObject xmlObject, String xpath )
{
List<Node> result = new ArrayList<Node>();
XmlCursor cursor = xmlObject.newCursor();
try
{
cursor.selectPath( xpath );
while( cursor.toNextSelection() )
{
result.add( cursor.getDomNode() );
}
}
finally
{
cursor.dispose();
}
return result.toArray( new Node[result.size()] );
}
private final static class ElementNodeList implements NodeList
{
private final List<Element> list;
public ElementNodeList( List<Element> list )
{
this.list = list;
}
public int getLength()
{
return list.size();
}
public Node item( int index )
{
return list.get( index );
}
}
public static boolean seemsToBeXml( String str )
{
try
{
if( StringUtils.isNullOrEmpty( str ) )
return false;
XmlObject.Factory.parse( str );
// SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
// saxParserFactory.setNamespaceAware( true );
// saxParserFactory.setValidating( false );
// saxParserFactory.setFeature( XMLConstants.FEATURE_SECURE_PROCESSING,
// true );
// SAXParser p = saxParserFactory.newSAXParser();
// p.parse( new StringInputStream( str ), new HandlerBase()
// {
//
// @Override
// public InputSource resolveEntity( String arg0, String arg1 ) throws
// SAXException
// {
// return null;
// }
// } );
return true;
}
catch( Throwable e )
{
return false;
}
}
public static String extractNamespaces( String xpath )
{
String result = xpath;
int ix = xpath.lastIndexOf( "declare namespace" );
if( ix != -1 )
{
ix = xpath.indexOf( '\'', ix + 1 );
if( ix != -1 )
{
ix = xpath.indexOf( '\'', ix + 1 );
if( ix != -1 )
{
ix = xpath.indexOf( ';' );
if( ix != -1 )
{
result = xpath.substring( 0, ix + 1 );
}
}
}
}
else
{
result = "";
}
return result;
}
public static String removeUnneccessaryNamespaces( String xml )
{
if( StringUtils.isNullOrEmpty( xml ) )
return xml;
XmlObject xmlObject = null;
XmlCursor cursor = null;
try
{
xmlObject = XmlObject.Factory.parse( xml );
cursor = xmlObject.newCursor();
while( cursor.currentTokenType() != TokenType.START && cursor.currentTokenType() != TokenType.ENDDOC )
{
cursor.toNextToken();
}
if( cursor.currentTokenType() == TokenType.START )
{
Map<?, ?> nsMap = new HashMap<Object, Object>();
cursor.getAllNamespaces( nsMap );
nsMap.remove( cursor.getDomNode().getPrefix() );
NamedNodeMap attributes = cursor.getDomNode().getAttributes();
for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
{
nsMap.remove( attributes.item( c ).getPrefix() );
}
if( cursor.toFirstChild() )
{
while( cursor.getDomNode() != xmlObject.getDomNode() )
{
attributes = cursor.getDomNode().getAttributes();
for( int c = 0; attributes != null && c < attributes.getLength(); c++ )
{
nsMap.remove( attributes.item( c ).getPrefix() );
}
nsMap.remove( cursor.getDomNode().getPrefix() );
cursor.toNextToken();
}
}
xml = xmlObject.xmlText( new XmlOptions().setSaveOuter().setSavePrettyPrint()
.setSaveImplicitNamespaces( nsMap ) );
}
}
catch( XmlException e )
{
}
finally
{
if( cursor != null )
cursor.dispose();
}
return xml;
}
public static String replaceNameInPathOrQuery( String pathOrQuery, String oldName, String newName ) throws Exception
{
Tokenizer t = new Tokenizer();
t.tokenize( pathOrQuery, 0, -1, 1 );
StringBuffer result = new StringBuffer();
int lastIx = 0;
while( t.currentToken != Token.EOF )
{
if( t.currentToken == Token.NAME && t.currentTokenValue.equals( oldName ) )
{
result.append( pathOrQuery.substring( lastIx, t.currentTokenStartOffset ) );
result.append( newName );
lastIx = t.currentTokenStartOffset + t.currentTokenValue.length();
}
t.next();
}
if( lastIx < pathOrQuery.length() )
result.append( pathOrQuery.substring( lastIx ) );
//
System.out.println( "returning " + result.toString() );
return result.toString();
}
public static QName getQName( XmlObject contentElement )
{
return contentElement == null ? null : getQName( contentElement.getDomNode() );
}
public static String getXPathValue( String value, String xpath )
{
try
{
XmlObject xmlObject = XmlObject.Factory.parse( value );
XmlObject[] nodes = xmlObject.selectPath( xpath );
if( nodes.length > 0 )
return getNodeValue( nodes[0].getDomNode() );
}
catch( XmlException e )
{
e.printStackTrace();
}
return null;
}
public static String createJdbcXmlResult( Statement statement ) throws SQLException, ParserConfigurationException
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
org.w3c.dom.Document xmlDocumentResult = builder.newDocument();
Element resultsElement = xmlDocumentResult.createElement( "Results" );
xmlDocumentResult.appendChild( resultsElement );
if( statement != null )
{
ResultSet resultSet = statement.getResultSet();
if( resultSet != null )
{
resultSet.setFetchSize( statement.getFetchSize() );
xmlDocumentResult = addResultSetXmlPart( resultsElement, resultSet, xmlDocumentResult );
while( statement.getMoreResults() )
{
xmlDocumentResult = addResultSetXmlPart( resultsElement, statement.getResultSet(), xmlDocumentResult );
}
}
else
{
Element errorElement = xmlDocumentResult.createElement( "UpdateCount" );
errorElement.appendChild( xmlDocumentResult.createTextNode( String.valueOf( statement.getUpdateCount() ) ) );
resultsElement.appendChild( errorElement );
}
}
StringWriter out = new StringWriter();
OutputFormat outputFormat = new OutputFormat( xmlDocumentResult );
outputFormat.setOmitComments( true );
outputFormat.setOmitDocumentType( true );
outputFormat.setOmitXMLDeclaration( true );
// outputFormat.setLineSeparator( "\n" );
// add this line //
// outputFormat.setPreserveSpace( true );
outputFormat.setIndent( 3 );
outputFormat.setIndenting( true );
try
{
XMLSerializer serializer = new XMLSerializer( new PrintWriter( out ), outputFormat );
serializer.asDOMSerializer();
serializer.serialize( xmlDocumentResult );
}
catch( IOException e )
{
SoapUI.logError( e );
}
return out.toString();
}
public static Document addResultSetXmlPart( Element resultsElement, ResultSet rs, Document xmlDocumentResult )
throws SQLException
{
// resultSet = statement.getResultSet();
// connection to an ACCESS MDB
ResultSetMetaData rsmd = rs.getMetaData();
Element resultSetElement = xmlDocumentResult.createElement( "ResultSet" );
resultSetElement.setAttribute( "fetchSize", String.valueOf( rs.getFetchSize() ) );
resultsElement.appendChild( resultSetElement );
int colCount = rsmd.getColumnCount();
while( rs.next() )
{
Element rowElement = xmlDocumentResult.createElement( "Row" );
rowElement.setAttribute( "rowNumber", String.valueOf( rs.getRow() ) );
resultsElement.appendChild( rowElement );
for( int ii = 1; ii <= colCount; ii++ )
{
String columnName = "";
if( !StringUtils.isNullOrEmpty( rsmd.getTableName( ii ) ) )
{
columnName += ( rsmd.getTableName( ii ) ).toUpperCase() + ".";
}
columnName += ( rsmd.getColumnName( ii ) ).toUpperCase();
String value = rs.getString( ii );
Element node = xmlDocumentResult.createElement( StringUtils.createXmlName( columnName ) );
if( !StringUtils.isNullOrEmpty( value ) )
{
Text textNode = xmlDocumentResult.createTextNode( value.toString() );
node.appendChild( textNode );
}
rowElement.appendChild( node );
}
resultSetElement.appendChild( rowElement );
}
return xmlDocumentResult;
}
}