View Javadoc

    1   /*
    2    *  soapUI, copyright (C) 2004-2007 eviware.com
    3    *
    4    *  soapUI is free software; you can redistribute it and/or modify it under the
    5    *  terms of version 2.1 of the GNU Lesser General Public License as published by
    6    *  the Free Software Foundation.
    7    *
    8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
    9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    10   *  See the GNU Lesser General Public License for more details at gnu.org.
    11   */
    12
    13  package com.eviware.soapui.impl.wsdl.support.xsd;
    14
    15  import java.io.File;
    16  import java.io.IOException;
    17  import java.net.MalformedURLException;
    18  import java.net.URL;
    19  import java.util.ArrayList;
    20  import java.util.Collection;
    21  import java.util.HashMap;
    22  import java.util.HashSet;
    23  import java.util.List;
    24  import java.util.Map;
    25  import java.util.Set;
    26  import java.util.StringTokenizer;
    27
    28  import javax.xml.namespace.QName;
    29
    30  import org.apache.log4j.Logger;
    31  import org.apache.xmlbeans.SchemaAnnotation;
    32  import org.apache.xmlbeans.SchemaLocalElement;
    33  import org.apache.xmlbeans.SchemaParticle;
    34  import org.apache.xmlbeans.SchemaType;
    35  import org.apache.xmlbeans.SchemaTypeLoader;
    36  import org.apache.xmlbeans.SchemaTypeSystem;
    37  import org.apache.xmlbeans.SimpleValue;
    38  import org.apache.xmlbeans.XmlAnySimpleType;
    39  import org.apache.xmlbeans.XmlBase64Binary;
    40  import org.apache.xmlbeans.XmlBeans;
    41  import org.apache.xmlbeans.XmlCursor;
    42  import org.apache.xmlbeans.XmlException;
    43  import org.apache.xmlbeans.XmlHexBinary;
    44  import org.apache.xmlbeans.XmlObject;
    45  import org.apache.xmlbeans.XmlOptions;
    46  import org.w3c.dom.Document;
    47  import org.w3c.dom.Element;
    48  import org.w3c.dom.NamedNodeMap;
    49  import org.w3c.dom.Node;
    50
    51  import com.eviware.soapui.SoapUI;
    52  import com.eviware.soapui.impl.wsdl.support.Constants;
    53  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
    54  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlLoader;
    55  import com.eviware.soapui.model.settings.SettingsListener;
    56  import com.eviware.soapui.settings.WsdlSettings;
    57  import com.eviware.soapui.support.StringUtils;
    58  import com.eviware.soapui.support.Tools;
    59  import com.eviware.soapui.support.types.StringList;
    60
    61  /***
    62   * XML-Schema related tools
    63   *
    64   * @author Ole.Matzura
    65   */
    66
    67  public class SchemaUtils
    68  {
    69     private final static Logger log = Logger.getLogger( SchemaUtils.class );
    70  	private static Map<String,XmlObject> defaultSchemas = new HashMap<String,XmlObject>();
    71
    72     static
    73     {
    74     	initDefaultSchemas();
    75
    76     	SoapUI.getSettings().addSettingsListener( new SettingsListener() {
    77
    78  			public void settingChanged( String name, String newValue, String oldValue )
    79  			{
    80  				if( name.equals( WsdlSettings.SCHEMA_DIRECTORY ))
    81  				{
    82  					log.info( "Reloading default schemas.." );
    83  					initDefaultSchemas();
    84  				}
    85  			}});
    86     }
    87
    88  	public static void initDefaultSchemas()
    89  	{
    90  		ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    91     	Thread.currentThread().setContextClassLoader( SoapUI.class.getClassLoader() );
    92
    93     	try
    94  		{
    95     		defaultSchemas.clear();
    96     		loadDefaultSchema( SoapUI.class.getResource("/xop.xsd") );
    97     		loadDefaultSchema( SoapUI.class.getResource("/XMLSchema.xsd") );
    98     		loadDefaultSchema( SoapUI.class.getResource("/xml.xsd") );
    99     		loadDefaultSchema( SoapUI.class.getResource("/swaref.xsd") );
    100    		loadDefaultSchema( SoapUI.class.getResource("/xmime200505.xsd") );
    101    		loadDefaultSchema( SoapUI.class.getResource("/xmime200411.xsd") );
    102
    103    		String schemaDirectory = SoapUI.getSettings().getString( WsdlSettings.SCHEMA_DIRECTORY, null );
    104    		if( StringUtils.hasContent( schemaDirectory ) )
    105    			loadSchemaDirectory( schemaDirectory );
    106 		}
    107 		catch (Exception e)
    108 		{
    109 			SoapUI.logError( e );
    110 		}
    111 		finally
    112    	{
    113    		Thread.currentThread().setContextClassLoader( contextClassLoader );
    114    	}
    115 	}
    116
    117 	private static void loadSchemaDirectory( String schemaDirectory ) throws IOException, MalformedURLException
    118 	{
    119 		File dir = new File( schemaDirectory );
    120 		if( dir.exists() && dir.isDirectory() )
    121 		{
    122 			String[] xsdFiles = dir.list();
    123 			int cnt = 0;
    124
    125 			if( xsdFiles != null && xsdFiles.length > 0 )
    126 			{
    127 				for( int c = 0; c < xsdFiles.length; c++ )
    128 				{
    129 					try
    130 					{
    131 						String xsdFile = xsdFiles[c];
    132 						if( xsdFile.endsWith( ".xsd" ))
    133 						{
    134 							String filename = schemaDirectory + File.separator + xsdFile;
    135 							loadDefaultSchema( new URL( "file:" + filename ) );
    136 							cnt++;
    137 						}
    138 					}
    139 					catch( Exception e )
    140 					{
    141 						SoapUI.logError( e );
    142 					}
    143 				}
    144 			}
    145
    146 			if( cnt == 0 )
    147 				log.warn( "Missing schema files in  schemaDirectory [" + schemaDirectory + "]" );
    148 		}
    149 		else log.warn( "Failed to open schemaDirectory [" + schemaDirectory + "]" );
    150 	}
    151
    152    private static void loadDefaultSchema( URL url ) throws XmlException, IOException
    153    {
    154    	XmlObject xmlObject = XmlObject.Factory.parse( url );
    155 		String targetNamespace = getTargetNamespace( xmlObject );
    156
    157 		if( defaultSchemas.containsKey( targetNamespace  ))
    158 			log.warn( "Overriding schema for targetNamespace " + targetNamespace );
    159
    160 		defaultSchemas.put(  targetNamespace, xmlObject );
    161
    162 		log.info( "Added default schema from " + url.getPath() + " with targetNamespace " + targetNamespace );
    163    }
    164
    165    public static SchemaTypeLoader loadSchemaTypes(String wsdlUrl, SoapVersion soapVersion, WsdlLoader loader ) throws SchemaException
    166    {
    167    	ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    168    	Thread.currentThread().setContextClassLoader( SoapUI.class.getClassLoader() );
    169
    170    	try
    171 		{
    172 			log.info("Loading schema types from [" + wsdlUrl + "]");
    173 			ArrayList<XmlObject> schemas = new ArrayList<XmlObject>(getSchemas(
    174 					wsdlUrl, loader).values());
    175
    176 			return buildSchemaTypes(schemas, soapVersion);
    177 		}
    178 		catch (Exception e)
    179 		{
    180 			throw new SchemaException( "Error loading schema types", e );
    181 		}
    182 		finally
    183    	{
    184    		Thread.currentThread().setContextClassLoader( contextClassLoader );
    185    	}
    186    }
    187
    188    public static SchemaTypeLoader buildSchemaTypes(List<XmlObject> schemas, SoapVersion soapVersion) throws SchemaException
    189    {
    190       XmlOptions options = new XmlOptions();
    191       options.setCompileNoValidation();
    192       options.setCompileNoPvrRule();
    193       options.setCompileDownloadUrls();
    194       options.setCompileNoUpaRule();
    195       options.setValidateTreatLaxAsSkip();
    196
    197       for( int c = 0; c < schemas.size(); c++ )
    198       {
    199       	XmlObject xmlObject = schemas.get(c);
    200       	if( xmlObject == null || !((Document)xmlObject.getDomNode()).getDocumentElement().getNamespaceURI().equals( Constants.XSD_NS ))
    201       	{
    202       		schemas.remove( c );
    203       		c--;
    204       	}
    205       }
    206
    207       if( !SoapUI.getSettings().getBoolean( WsdlSettings.STRICT_SCHEMA_TYPES ))
    208       {
    209          Set<String> mdefNamespaces = new HashSet<String>();
    210
    211          for (XmlObject xObj: schemas)
    212          {
    213          	mdefNamespaces.add( getTargetNamespace( xObj ) );
    214          }
    215
    216          options.setCompileMdefNamespaces(mdefNamespaces);
    217       }
    218
    219       ArrayList errorList = new ArrayList();
    220       options.setErrorListener( errorList );
    221
    222       XmlCursor cursor = null;
    223
    224       try
    225 		{
    226       	// remove imports
    227 			for( int c = 0; c < schemas.size(); c++ )
    228 			{
    229 				XmlObject s = schemas.get( c );
    230
    231 				Map map = new HashMap();
    232 				cursor = s.newCursor();
    233 				cursor.toStartDoc();
    234 				if( toNextContainer(cursor))
    235 					cursor.getAllNamespaces( map );
    236 				else
    237 					log.warn( "Can not get namespaces for " + s );
    238
    239 				String tns = getTargetNamespace(s);
    240
    241 				log.info( "schema for [" + tns + "] contained [" + map.toString() + "] namespaces" );
    242
    243
    244 				if( defaultSchemas.containsKey( tns ) ||
    245 					 tns.equals( getTargetNamespace(soapVersion.getSoapEncodingSchema()) ) ||
    246 					 tns.equals( getTargetNamespace(soapVersion.getSoapEnvelopeSchema() )))
    247 				{
    248 					schemas.remove( c );
    249 					c--;
    250 				}
    251 				else
    252 				{
    253 					removeImports(s);
    254 				}
    255
    256 				cursor.dispose();
    257 				cursor = null;
    258 			}
    259
    260       	schemas.add( soapVersion.getSoapEncodingSchema());
    261       	schemas.add( soapVersion.getSoapEnvelopeSchema());
    262       	schemas.addAll( defaultSchemas.values() );
    263
    264       	SchemaTypeSystem sts = XmlBeans.compileXsd(
    265       			schemas.toArray(new XmlObject[schemas.size()]), XmlBeans.getBuiltinTypeSystem(), options);
    266       	return XmlBeans.typeLoaderUnion(new SchemaTypeLoader[] { sts, XmlBeans.getBuiltinTypeSystem() });
    267 		}
    268 		catch (Exception e)
    269 		{
    270 			SoapUI.logError( e );
    271 			throw new SchemaException( e, errorList );
    272 		}
    273 		finally
    274 		{
    275 			for( int c = 0; c < errorList.size(); c++ )
    276 			{
    277 				log.warn( "Error: " + errorList.get( c ));
    278 			}
    279
    280 			if( cursor != null )
    281 				cursor.dispose();
    282 		}
    283    }
    284
    285 	public static boolean toNextContainer(XmlCursor cursor)
    286 	{
    287 		while( !cursor.isContainer() && !cursor.isEnddoc() )
    288 			cursor.toNextToken();
    289
    290 		return cursor.isContainer();
    291 	}
    292
    293 	public static String getTargetNamespace(XmlObject s)
    294 	{
    295 		return ((Document)s.getDomNode()).getDocumentElement().getAttribute( "targetNamespace" );
    296 	}
    297
    298    public static Map<String,XmlObject> getSchemas( String wsdlUrl, WsdlLoader loader ) throws SchemaException
    299    {
    300    	Map<String,XmlObject> result = new HashMap<String,XmlObject>();
    301    	getSchemas( wsdlUrl, result, loader, null, false );
    302    	return result;
    303    }
    304
    305    /***
    306     * Returns a map mapping urls to corresponding XmlSchema XmlObjects for the specified wsdlUrl
    307     */
    308
    309    public static void getSchemas( String wsdlUrl, Map<String,XmlObject> existing,  WsdlLoader loader, String tns, boolean add ) throws SchemaException
    310    {
    311    	if( existing.containsKey( wsdlUrl ))
    312    		return;
    313
    314    	if( add )
    315    		existing.put( wsdlUrl, null );
    316
    317    	log.info( "Getting schema " + wsdlUrl );
    318
    319    	ArrayList errorList = new ArrayList();
    320
    321    	Map<String,XmlObject> result = new HashMap<String,XmlObject>();
    322
    323       try
    324 		{
    325 			XmlOptions options = new XmlOptions();
    326 			options.setCompileNoValidation();
    327 			options.setSaveUseOpenFrag();
    328 			options.setErrorListener( errorList );
    329 			options.setSaveSyntheticDocumentElement(new QName( Constants.XSD_NS, "schema"));
    330
    331 			XmlObject xmlObject = loader.loadXmlObject(wsdlUrl, options);
    332
    333 			Document dom = (Document) xmlObject.getDomNode();
    334 			Node domNode = dom.getDocumentElement();
    335 			if (domNode.getLocalName().equals("schema")
    336 					&& domNode.getNamespaceURI().equals(
    337 							Constants.XSD_NS))
    338 			{
    339 				// set targetNamespace (this happens if we are following an include statement)
    340 				if( tns != null )
    341 				{
    342 					Element elm = ((Element)domNode);
    343 					if( !elm.hasAttribute( "targetNamespace" ))
    344 					{
    345 						elm.setAttribute( "targetNamespace", tns );
    346 					}
    347
    348 					// check for namespace prefix for targetNamespace
    349 					NamedNodeMap attributes = elm.getAttributes();
    350 					int c = 0;
    351 					for( ; c < attributes.getLength(); c++ )
    352 					{
    353 						Node item = attributes.item( c );
    354 						if( item.getNodeValue().equals( tns ) && item.getNodeName().startsWith( "xmlns" ))
    355 							break;
    356 					}
    357
    358 					if( c == attributes.getLength() )
    359 						elm.setAttribute( "xmlns", tns );
    360 				}
    361
    362 				result.put(wsdlUrl, xmlObject);
    363 			}
    364 			else
    365 			{
    366 				XmlObject[] schemas = xmlObject
    367 						.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:schema");
    368
    369 				for (int i = 0; i < schemas.length; i++)
    370 				{
    371 					XmlCursor xmlCursor = schemas[i].newCursor();
    372 					String xmlText = xmlCursor.getObject().xmlText(options);
    373 					schemas[i] = XmlObject.Factory.parse(xmlText, options);
    374 					schemas[i].documentProperties().setSourceName(wsdlUrl);
    375
    376 					result.put(wsdlUrl + "@" + (i+1), schemas[i]);
    377 				}
    378
    379 				XmlObject[] wsdlImports = xmlObject
    380 						.selectPath("declare namespace s='" + Constants.WSDL11_NS + "' .//s:import/@location");
    381 				for (int i = 0; i < wsdlImports.length; i++)
    382 				{
    383 					String location = ((SimpleValue) wsdlImports[i]).getStringValue();
    384 					if (location != null)
    385 					{
    386 						if ( !location.startsWith("file:") && location.indexOf("://") == -1 )
    387 							location = Tools.joinRelativeUrl(wsdlUrl, location);
    388
    389 						getSchemas(location, existing, loader, null, true );
    390 					}
    391 				}
    392 			}
    393
    394 			existing.putAll( result );
    395
    396 			XmlObject[] schemas = result.values().toArray(
    397 					new XmlObject[result.size()]);
    398
    399 			for (int c = 0; c < schemas.length; c++)
    400 			{
    401 				xmlObject = schemas[c];
    402
    403 				XmlObject[] schemaImports = xmlObject
    404 						.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:import/@schemaLocation");
    405 				for (int i = 0; i < schemaImports.length; i++)
    406 				{
    407 					String location = ((SimpleValue) schemaImports[i])
    408 							.getStringValue();
    409 					if (location != null)
    410 					{
    411 						if ( !location.startsWith("file:") && location.indexOf("://") == -1 )
    412 							location = Tools.joinRelativeUrl(wsdlUrl, location);
    413
    414 						getSchemas(location, existing, loader, null, false );
    415 					}
    416 				}
    417
    418 				XmlObject[] schemaIncludes = xmlObject
    419 						.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:include/@schemaLocation");
    420 				for (int i = 0; i < schemaIncludes.length; i++)
    421 				{
    422 					String location = ((SimpleValue) schemaIncludes[i])
    423 							.getStringValue();
    424 					if (location != null)
    425 					{
    426 						String targetNS = getTargetNamespace( xmlObject );
    427
    428 						if ( !location.startsWith("file:") && location.indexOf("://") == -1 )
    429 							location = Tools.joinRelativeUrl(wsdlUrl, location);
    430
    431 						getSchemas(location, existing, loader, targetNS, false );
    432 					}
    433 				}
    434 			}
    435 		}
    436 		catch (Exception e)
    437 		{
    438 			SoapUI.logError( e );
    439 			throw new SchemaException( e, errorList );
    440 		}
    441    }
    442
    443    /***
    444     * Returns a map mapping urls to corresponding XmlObjects for the specified wsdlUrl
    445     */
    446
    447    public static Map<String,XmlObject> getDefinitionParts( WsdlLoader loader ) throws Exception
    448    {
    449    	HashMap<String, XmlObject> result = new HashMap<String,XmlObject>();
    450 		getDefinitionParts( loader.getBaseURI(), result, loader );
    451 		return result;
    452    }
    453
    454    public static void getDefinitionParts( String wsdlUrl, Map<String,XmlObject> existing, WsdlLoader loader ) throws Exception
    455    {
    456    	if( existing.containsKey( wsdlUrl ))
    457    		return;
    458
    459       XmlObject xmlObject = loader.loadXmlObject( wsdlUrl, null );
    460       existing.put( wsdlUrl, xmlObject );
    461
    462     	XmlObject [] wsdlImports = xmlObject.selectPath("declare namespace s='" + Constants.WSDL11_NS + "' .//s:import");
    463       for (int i = 0; i < wsdlImports.length; i++)
    464       {
    465          String location = wsdlImports[i].getDomNode().getAttributes().getNamedItem( "location" ).getNodeValue();
    466          if( location != null )
    467          {
    468          	if ( !location.startsWith("file:") && location.indexOf("://") == -1 )
    469 					location = Tools.joinRelativeUrl(wsdlUrl, location);
    470
    471            	getDefinitionParts( location, existing, loader );
    472          }
    473       }
    474
    475       XmlObject[] schemaImports = xmlObject.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:import/@schemaLocation");
    476       for (int i = 0; i < schemaImports.length; i++)
    477       {
    478          String location = ((SimpleValue)schemaImports[i]).getStringValue();
    479          if( location != null )
    480          {
    481          	if ( !location.startsWith("file:") && location.indexOf("://") == -1 )
    482 					location = Tools.joinRelativeUrl(wsdlUrl, location);
    483
    484          	getDefinitionParts( location, existing, loader );
    485          }
    486       }
    487
    488       XmlObject[] schemaIncludes = xmlObject.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:include/@schemaLocation");
    489       for (int i = 0; i < schemaIncludes.length; i++)
    490       {
    491          String location = ((SimpleValue)schemaIncludes[i]).getStringValue();
    492          if( location != null  )
    493          {
    494          	if ( !location.startsWith("file:") && location.indexOf("://") == -1 )
    495 					location = Tools.joinRelativeUrl(wsdlUrl, location);
    496
    497          	getDefinitionParts( location, existing, loader );
    498          }
    499       }
    500    }
    501
    502    /***
    503     * Extracts namespaces - used in tool integrations for mapping..
    504     */
    505
    506 	public static Collection<String> extractNamespaces( SchemaTypeSystem schemaTypes, boolean removeDefault )
    507 	{
    508 		Set<String> namespaces = new HashSet<String>();
    509 		SchemaType[] globalTypes = schemaTypes.globalTypes();
    510 		for( int c = 0; c < globalTypes.length; c++ )
    511 		{
    512 			namespaces.add( globalTypes[c].getName().getNamespaceURI() );
    513 		}
    514
    515 		if( removeDefault )
    516 		{
    517 			namespaces.removeAll( defaultSchemas.keySet() );
    518 			namespaces.remove( Constants.SOAP11_ENVELOPE_NS );
    519 			namespaces.remove( Constants.SOAP_ENCODING_NS );
    520 		}
    521
    522 		return namespaces;
    523 	}
    524
    525    /***
    526     * Used when creating a TypeSystem from a complete collection of SchemaDocuments so that referenced
    527     * types are not downloaded (again)
    528     */
    529
    530 	public static void removeImports(XmlObject xmlObject) throws XmlException
    531 	{
    532 		 XmlObject[] imports = xmlObject
    533        	.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:import");
    534
    535 		 for( int c = 0; c < imports.length; c++ )
    536 		 {
    537 			 XmlCursor cursor = imports[c].newCursor();
    538 			 cursor.removeXml();
    539 			 cursor.dispose();
    540 		 }
    541
    542 		 XmlObject[] includes = xmlObject
    543      		.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:include");
    544
    545 		 for( int c = 0; c < includes.length; c++ )
    546 		 {
    547 			 XmlCursor cursor = includes[c].newCursor();
    548 			 cursor.removeXml();
    549 			 cursor.dispose();
    550 		 }
    551 	}
    552
    553 	public static boolean isInstanceOf( SchemaType schemaType, SchemaType baseType )
    554 	{
    555 		if( schemaType == null )
    556 			return false;
    557 		return schemaType.equals(baseType) ? true : isInstanceOf( schemaType.getBaseType(), baseType );
    558 	}
    559
    560 	public static boolean isBinaryType(SchemaType schemaType)
    561 	{
    562 		return isInstanceOf( schemaType, XmlHexBinary.type ) ||
    563 				isInstanceOf( schemaType, XmlBase64Binary.type );
    564 	}
    565
    566 	public static String getDocumentation( SchemaParticle particle, SchemaType schemaType )
    567 	{
    568 		String result = null;
    569 		String xsPrefix = null;
    570
    571 		if( particle instanceof SchemaLocalElement )
    572 		{
    573 			SchemaAnnotation annotation = ((SchemaLocalElement)particle).getAnnotation();
    574 			if( annotation != null )
    575 			{
    576 				XmlObject[] userInformation = annotation.getUserInformation();
    577 				if( userInformation != null && userInformation.length > 0 )
    578 				{
    579 					XmlObject xmlObject = userInformation[0];
    580 					XmlCursor cursor = xmlObject.newCursor();
    581 					xsPrefix = cursor.prefixForNamespace( "http://www.w3.org/2001/XMLSchema" );
    582 					cursor.dispose();
    583
    584 					result = xmlObject.xmlText(); // XmlUtils.getElementText( ( Element ) userInformation[0].getDomNode());
    585 				}
    586 			}
    587 		}
    588
    589 		if( result == null && schemaType != null && schemaType.getAnnotation() != null )
    590 		{
    591 			XmlObject[] userInformation = schemaType.getAnnotation().getUserInformation();
    592 			if( userInformation != null && userInformation.length > 0 )
    593 			{
    594 				XmlObject xmlObject = userInformation[0];
    595 				XmlCursor cursor = xmlObject.newCursor();
    596 				xsPrefix = cursor.prefixForNamespace( "http://www.w3.org/2001/XMLSchema" );
    597 				cursor.dispose();
    598 				result = xmlObject.xmlText(); // = XmlUtils.getElementText( ( Element ) userInformation[0].getDomNode());
    599 			}
    600 		}
    601
    602 		if( result != null )
    603 		{
    604 			result = result.trim();
    605 			if( result.startsWith( "<" ) && result.endsWith( ">" ))
    606 			{
    607 				int ix = result.indexOf( '>' );
    608 				if( ix > 0 )
    609 				{
    610 					result = result.substring( ix+1);
    611 				}
    612
    613 				ix = result.lastIndexOf( '<' );
    614 				if( ix >= 0 )
    615 				{
    616 					result = result.substring( 0, ix );
    617 				}
    618 			}
    619
    620 			if( xsPrefix == null || xsPrefix.length() == 0 )
    621 				xsPrefix = "xs:";
    622 			else
    623 				xsPrefix += ":";
    624
    625 			//result = result.trim().replaceAll( "<" + xsPrefix + "br/>", "\n" ).trim();
    626 			result = result.trim().replaceAll( xsPrefix, "" ).trim();
    627
    628 			result = toHtml( result );
    629 		}
    630
    631 		return result;
    632 	}
    633
    634 	public static String toHtml( String string )
    635 	{
    636 		StringTokenizer st = new StringTokenizer( string, "\r\n" );
    637 		StringBuffer buf = new StringBuffer( "<html><body>" );
    638 		boolean added = false;
    639
    640 		while( st.hasMoreElements() )
    641 		{
    642 			String str = st.nextToken().trim();
    643 			if( str.length() > 0 )
    644 			{
    645 				if( str.equals( "<br/>" ))
    646 				{
    647 					buf.append( "<br>" );
    648 					added = false;
    649 					continue;
    650 				}
    651
    652 				if( added )
    653 					buf.append( "<br>" );
    654
    655 				buf.append( str );
    656 				added = true;
    657 			}
    658 		}
    659 		buf.append( "</body></html>" );
    660 		string = buf.toString();
    661 		return string;
    662 	}
    663
    664 	public static String [] getEnumerationValues( SchemaType schemaType, boolean addNull )
    665 	{
    666 		if( schemaType != null )
    667 		{
    668 			XmlAnySimpleType[] enumerationValues = schemaType.getEnumerationValues();
    669 			if( enumerationValues != null && enumerationValues.length > 0 )
    670 			{
    671 				if( addNull )
    672 				{
    673 					String [] values = new String[enumerationValues.length+1];
    674 					values[0] = null;
    675
    676 					for( int c = 1; c < values.length; c++ )
    677 						values[c] = enumerationValues[c-1].getStringValue();
    678
    679 					return values;
    680 				}
    681 				else
    682 				{
    683 					String [] values = new String[enumerationValues.length];
    684
    685 					for( int c = 0; c < values.length; c++ )
    686 						values[c] = enumerationValues[c].getStringValue();
    687
    688 					return values;
    689 				}
    690 			}
    691 		}
    692
    693 		return new String[0];
    694 	}
    695
    696 	public static Collection<? extends QName> getExcludedTypes()
    697 	{
    698 		List<QName> result = new ArrayList<QName>();
    699
    700 		String excluded = SoapUI.getSettings().getString( WsdlSettings.EXCLUDED_TYPES, null );
    701 	   if( excluded != null && excluded.trim().length() > 0 )
    702 	   {
    703 	 	  	try
    704 			{
    705 			   StringList names = StringList.fromXml( excluded );
    706 			   for( String name : names )
    707 			   {
    708 			   	int ix = name.indexOf( '@' );
    709 			   	result.add( new QName( name.substring( ix+1 ), name.substring( 0, ix )));
    710 			   }
    711 		 	}
    712 			catch( Exception e )
    713 			{
    714 				SoapUI.logError( e );
    715 			}
    716 	   }
    717
    718 		return result;
    719 	}
    720 }