View Javadoc

1   /*   Copyright 2004 The Apache Software Foundation
2    *
3    *   Licensed under the Apache License, Version 2.0 (the "License");
4    *   you may not use this file except in compliance with the License.
5    *   You may obtain a copy of the License at
6    *
7    *       http://www.apache.org/licenses/LICENSE-2.0
8    *
9    *   Unless required by applicable law or agreed to in writing, software
10   *   distributed under the License is distributed on an "AS IS" BASIS,
11   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   *   See the License for the specific language governing permissions and
13   *  limitations under the License.
14   */
15  
16  package com.eviware.soapui.impl.wsdl.support.xsd;
17  
18  import java.math.BigDecimal;
19  import java.math.BigInteger;
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.Calendar;
23  import java.util.Date;
24  import java.util.HashSet;
25  import java.util.Random;
26  import java.util.Set;
27  
28  import javax.xml.namespace.QName;
29  
30  import org.apache.xmlbeans.GDate;
31  import org.apache.xmlbeans.GDateBuilder;
32  import org.apache.xmlbeans.GDuration;
33  import org.apache.xmlbeans.GDurationBuilder;
34  import org.apache.xmlbeans.SchemaLocalElement;
35  import org.apache.xmlbeans.SchemaParticle;
36  import org.apache.xmlbeans.SchemaProperty;
37  import org.apache.xmlbeans.SchemaType;
38  import org.apache.xmlbeans.SimpleValue;
39  import org.apache.xmlbeans.XmlAnySimpleType;
40  import org.apache.xmlbeans.XmlCursor;
41  import org.apache.xmlbeans.XmlDate;
42  import org.apache.xmlbeans.XmlDateTime;
43  import org.apache.xmlbeans.XmlDecimal;
44  import org.apache.xmlbeans.XmlDuration;
45  import org.apache.xmlbeans.XmlGDay;
46  import org.apache.xmlbeans.XmlGMonth;
47  import org.apache.xmlbeans.XmlGMonthDay;
48  import org.apache.xmlbeans.XmlGYear;
49  import org.apache.xmlbeans.XmlGYearMonth;
50  import org.apache.xmlbeans.XmlInteger;
51  import org.apache.xmlbeans.XmlObject;
52  import org.apache.xmlbeans.XmlOptions;
53  import org.apache.xmlbeans.XmlTime;
54  import org.apache.xmlbeans.impl.util.Base64;
55  import org.apache.xmlbeans.impl.util.HexBin;
56  import org.apache.xmlbeans.soap.SOAPArrayType;
57  import org.apache.xmlbeans.soap.SchemaWSDLArrayType;
58  
59  import com.eviware.soapui.SoapUI;
60  import com.eviware.soapui.settings.WsdlSettings;
61  
62  /***
63   * XmlBeans class for generating XML from XML Schemas
64   */
65  
66  public class SampleXmlUtil
67  {
68  	private boolean _soapEnc;
69  	private boolean _exampleContent = false;
70  	private boolean _typeComment = false;
71  	private Set<QName> excludedTypes = new HashSet<QName>();
72  	private boolean _skipComments;
73  
74  	public SampleXmlUtil( boolean soapEnc )
75  	{
76  		_soapEnc = soapEnc;
77  
78  		excludedTypes.addAll( SchemaUtils.getExcludedTypes() );
79  	}
80  
81  	public boolean isSoapEnc()
82  	{
83  		return _soapEnc;
84  	}
85  
86  	public boolean isExampleContent()
87  	{
88  		return _exampleContent;
89  	}
90  
91  	public void setExampleContent( boolean content )
92  	{
93  		_exampleContent = content;
94  	}
95  
96  	public boolean isTypeComment()
97  	{
98  		return _typeComment;
99  	}
100 
101 	public void setTypeComment( boolean comment )
102 	{
103 		_typeComment = comment;
104 	}
105 
106 	public String createSample( SchemaType sType )
107 	{
108 		XmlObject object = XmlObject.Factory.newInstance();
109 		XmlCursor cursor = object.newCursor();
110 		// Skip the document node
111 		cursor.toNextToken();
112 		// Using the type and the cursor, call the utility method to get a
113 		// sample XML payload for that Schema element
114 		createSampleForType( sType, cursor );
115 		// Cursor now contains the sample payload
116 		// Pretty print the result. Note that the cursor is positioned at the
117 		// end of the doc so we use the original xml object that the cursor was
118 		// created upon to do the xmlText() against.
119 
120 		cursor.dispose();
121 
122 		XmlOptions options = new XmlOptions();
123 		options.put( XmlOptions.SAVE_PRETTY_PRINT );
124 		options.put( XmlOptions.SAVE_PRETTY_PRINT_INDENT, 3 );
125 		options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
126 		options.setSaveOuter();
127 		String result = object.xmlText( options );
128 
129 		return result;
130 	}
131 
132 	public static String createSampleForType( SchemaType sType )
133 	{
134 		XmlObject object = XmlObject.Factory.newInstance();
135 		XmlCursor cursor = object.newCursor();
136 		// Skip the document node
137 		cursor.toNextToken();
138 		// Using the type and the cursor, call the utility method to get a
139 		// sample XML payload for that Schema element
140 		new SampleXmlUtil( false ).createSampleForType( sType, cursor );
141 		// Cursor now contains the sample payload
142 		// Pretty print the result. Note that the cursor is positioned at the
143 		// end of the doc so we use the original xml object that the cursor was
144 		// created upon to do the xmlText() against.
145 
146 		cursor.dispose();
147 		XmlOptions options = new XmlOptions();
148 		options.put( XmlOptions.SAVE_PRETTY_PRINT );
149 		options.put( XmlOptions.SAVE_PRETTY_PRINT_INDENT, 3 );
150 		options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
151 		options.setSaveOuter();
152 		String result = object.xmlText( options );
153 
154 		return result;
155 	}
156 
157 	Random _picker = new Random( 1 );
158 
159 	private boolean ignoreOptional;
160 
161 	/***
162 	 * Cursor position Before: <theElement>^</theElement> After: <theElement><lots
163 	 * of stuff/>^</theElement>
164 	 */
165 	public void createSampleForType( SchemaType stype, XmlCursor xmlc )
166 	{
167 		_exampleContent = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_TYPE_EXAMPLE_VALUE );
168 		_typeComment = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_TYPE_COMMENT_TYPE );
169 		_skipComments = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_SKIP_COMMENTS );
170 		
171 		QName nm = stype.getName();
172 		if( nm == null && stype.getContainerField() != null )
173 			nm = stype.getContainerField().getName();
174 
175 		if( nm != null && excludedTypes.contains( nm ) )
176 		{
177 			if( !_skipComments )
178 				xmlc.insertComment( "Ignoring type [" + nm + "]" );
179 			return;
180 		}
181 
182 		if( _typeStack.contains( stype ) )
183 			return;
184 
185 		_typeStack.add( stype );
186 
187 		try
188 		{
189 			if( stype.isSimpleType() || stype.isURType() )
190 			{
191 				processSimpleType( stype, xmlc );
192 				return;
193 			}
194 
195 			// complex Type
196 			// <theElement>^</theElement>
197 			processAttributes( stype, xmlc );
198 
199 			// <theElement attri1="string">^</theElement>
200 			switch( stype.getContentType() )
201 			{
202 			case SchemaType.NOT_COMPLEX_TYPE:
203 			case SchemaType.EMPTY_CONTENT:
204 				// noop
205 				break;
206 			case SchemaType.SIMPLE_CONTENT:
207 			{
208 				processSimpleType( stype, xmlc );
209 			}
210 				break;
211 			case SchemaType.MIXED_CONTENT:
212 				xmlc.insertChars( pick( WORDS ) + " " );
213 				if( stype.getContentModel() != null )
214 				{
215 					processParticle( stype.getContentModel(), xmlc, true );
216 				}
217 				xmlc.insertChars( pick( WORDS ) );
218 				break;
219 			case SchemaType.ELEMENT_CONTENT:
220 				if( stype.getContentModel() != null )
221 				{
222 					processParticle( stype.getContentModel(), xmlc, false );
223 				}
224 				break;
225 			}
226 		}
227 		finally
228 		{
229 			_typeStack.remove( _typeStack.size() - 1 );
230 		}
231 	}
232 
233 	private void processSimpleType( SchemaType stype, XmlCursor xmlc )
234 	{
235 		if( _soapEnc )
236 		{
237 			QName typeName = stype.getName();
238 			if( typeName != null )
239 			{
240 				xmlc.insertAttributeWithValue( XSI_TYPE, formatQName( xmlc, typeName ) );
241 			}
242 		}
243 
244 		String sample = sampleDataForSimpleType( stype );
245 		xmlc.insertChars( sample );
246 	}
247 
248 	private String sampleDataForSimpleType( SchemaType sType )
249 	{
250 		// swaRef
251 		if( sType.getName() != null )
252 		{
253 			if( sType.getName().equals( new QName( "http://ws-i.org/profiles/basic/1.1/xsd", "swaRef" ) ) )
254 				return "cid:" + ( long ) ( System.currentTimeMillis() * Math.random() );
255 
256 			// xmime base64
257 			if( sType.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "base64Binary" ) ) )
258 				return "cid:" + ( long ) ( System.currentTimeMillis() * Math.random() );
259 
260 			// xmime hexBinary
261 			if( sType.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "hexBinary" ) ) )
262 				return "cid:" + ( long ) ( System.currentTimeMillis() * Math.random() );
263 		}
264 
265 		SchemaType primitiveType = sType.getPrimitiveType();
266 		if( primitiveType != null
267 					&& ( primitiveType.getBuiltinTypeCode() == SchemaType.BTC_BASE_64_BINARY || primitiveType
268 								.getBuiltinTypeCode() == SchemaType.BTC_HEX_BINARY ) )
269 			return "cid:" + ( long ) ( System.currentTimeMillis() * Math.random() );
270 
271 		// if( sType != null )
272 		if( !_exampleContent )
273 			return "?";
274 
275 		if( XmlObject.type.equals( sType ) )
276 			return "anyType";
277 
278 		if( XmlAnySimpleType.type.equals( sType ) )
279 			return "anySimpleType";
280 
281 		if( sType.getSimpleVariety() == SchemaType.LIST )
282 		{
283 			SchemaType itemType = sType.getListItemType();
284 			StringBuffer sb = new StringBuffer();
285 			int length = pickLength( sType );
286 			if( length > 0 )
287 				sb.append( sampleDataForSimpleType( itemType ) );
288 			for( int i = 1; i < length; i += 1 )
289 			{
290 				sb.append( ' ' );
291 				sb.append( sampleDataForSimpleType( itemType ) );
292 			}
293 			return sb.toString();
294 		}
295 
296 		if( sType.getSimpleVariety() == SchemaType.UNION )
297 		{
298 			SchemaType[] possibleTypes = sType.getUnionConstituentTypes();
299 			if( possibleTypes.length == 0 )
300 				return "";
301 			return sampleDataForSimpleType( possibleTypes[pick( possibleTypes.length )] );
302 		}
303 
304 		XmlAnySimpleType[] enumValues = sType.getEnumerationValues();
305 		if( enumValues != null && enumValues.length > 0 )
306 		{
307 			return enumValues[pick( enumValues.length )].getStringValue();
308 		}
309 
310 		switch( primitiveType.getBuiltinTypeCode() )
311 		{
312 		default:
313 		case SchemaType.BTC_NOT_BUILTIN:
314 			return "";
315 
316 		case SchemaType.BTC_ANY_TYPE:
317 		case SchemaType.BTC_ANY_SIMPLE:
318 			return "anything";
319 
320 		case SchemaType.BTC_BOOLEAN:
321 			return pick( 2 ) == 0 ? "true" : "false";
322 
323 		case SchemaType.BTC_BASE_64_BINARY:
324 		{
325 			String result = null;
326 			try
327 			{
328 				result = new String( Base64.encode( formatToLength( pick( WORDS ), sType ).getBytes( "utf-8" ) ) );
329 			}
330 			catch( java.io.UnsupportedEncodingException e )
331 			{
332 			}
333 			return result;
334 		}
335 
336 		case SchemaType.BTC_HEX_BINARY:
337 			return HexBin.encode( formatToLength( pick( WORDS ), sType ) );
338 
339 		case SchemaType.BTC_ANY_URI:
340 			return formatToLength( "http://www." + pick( DNS1 ) + "." + pick( DNS2 ) + "/" + pick( WORDS ) + "/"
341 						+ pick( WORDS ), sType );
342 
343 		case SchemaType.BTC_QNAME:
344 			return formatToLength( "qname", sType );
345 
346 		case SchemaType.BTC_NOTATION:
347 			return formatToLength( "notation", sType );
348 
349 		case SchemaType.BTC_FLOAT:
350 			return "1.5E2";
351 		case SchemaType.BTC_DOUBLE:
352 			return "1.051732E7";
353 		case SchemaType.BTC_DECIMAL:
354 			switch( closestBuiltin( sType ).getBuiltinTypeCode() )
355 			{
356 			case SchemaType.BTC_SHORT:
357 				return formatDecimal( "1", sType );
358 			case SchemaType.BTC_UNSIGNED_SHORT:
359 				return formatDecimal( "5", sType );
360 			case SchemaType.BTC_BYTE:
361 				return formatDecimal( "2", sType );
362 			case SchemaType.BTC_UNSIGNED_BYTE:
363 				return formatDecimal( "6", sType );
364 			case SchemaType.BTC_INT:
365 				return formatDecimal( "3", sType );
366 			case SchemaType.BTC_UNSIGNED_INT:
367 				return formatDecimal( "7", sType );
368 			case SchemaType.BTC_LONG:
369 				return formatDecimal( "10", sType );
370 			case SchemaType.BTC_UNSIGNED_LONG:
371 				return formatDecimal( "11", sType );
372 			case SchemaType.BTC_INTEGER:
373 				return formatDecimal( "100", sType );
374 			case SchemaType.BTC_NON_POSITIVE_INTEGER:
375 				return formatDecimal( "-200", sType );
376 			case SchemaType.BTC_NEGATIVE_INTEGER:
377 				return formatDecimal( "-201", sType );
378 			case SchemaType.BTC_NON_NEGATIVE_INTEGER:
379 				return formatDecimal( "200", sType );
380 			case SchemaType.BTC_POSITIVE_INTEGER:
381 				return formatDecimal( "201", sType );
382 			default:
383 			case SchemaType.BTC_DECIMAL:
384 				return formatDecimal( "1000.00", sType );
385 			}
386 
387 		case SchemaType.BTC_STRING:
388 		{
389 			String result;
390 			switch( closestBuiltin( sType ).getBuiltinTypeCode() )
391 			{
392 			case SchemaType.BTC_STRING:
393 			case SchemaType.BTC_NORMALIZED_STRING:
394 				result = pick( WORDS, _picker.nextInt( 3 ) );
395 				break;
396 
397 			case SchemaType.BTC_TOKEN:
398 				result = pick( WORDS, _picker.nextInt( 3 ) );
399 				break;
400 
401 			default:
402 				result = pick( WORDS, _picker.nextInt( 3 ) );
403 				break;
404 			}
405 
406 			return formatToLength( result, sType );
407 		}
408 
409 		case SchemaType.BTC_DURATION:
410 			return formatDuration( sType );
411 
412 		case SchemaType.BTC_DATE_TIME:
413 		case SchemaType.BTC_TIME:
414 		case SchemaType.BTC_DATE:
415 		case SchemaType.BTC_G_YEAR_MONTH:
416 		case SchemaType.BTC_G_YEAR:
417 		case SchemaType.BTC_G_MONTH_DAY:
418 		case SchemaType.BTC_G_DAY:
419 		case SchemaType.BTC_G_MONTH:
420 			return formatDate( sType );
421 
422 		}
423 	}
424 
425 	// a bit from the Aenid
426 	public static final String[] WORDS = new String[] { "ipsa", "iovis", "rapidum", "iaculata", "e", "nubibus", "ignem",
427 				"disiecitque", "rates", "evertitque", "aequora", "ventis", "illum", "exspirantem", "transfixo", "pectore",
428 				"flammas", "turbine", "corripuit", "scopuloque", "infixit", "acuto", "ast", "ego", "quae", "divum",
429 				"incedo", "regina", "iovisque", "et", "soror", "et", "coniunx", "una", "cum", "gente", "tot", "annos",
430 				"bella", "gero", "et", "quisquam", "numen", "iunonis", "adorat", "praeterea", "aut", "supplex", "aris",
431 				"imponet", "honorem", "talia", "flammato", "secum", "dea", "corde", "volutans", "nimborum", "in",
432 				"patriam", "loca", "feta", "furentibus", "austris", "aeoliam", "venit", "hic", "vasto", "rex", "aeolus",
433 				"antro", "luctantis", "ventos", "tempestatesque", "sonoras", "imperio", "premit", "ac", "vinclis", "et",
434 				"carcere", "frenat", "illi", "indignantes", "magno", "cum", "murmure", "montis", "circum", "claustra",
435 				"fremunt", "celsa", "sedet", "aeolus", "arce", "sceptra", "tenens", "mollitque", "animos", "et",
436 				"temperat", "iras", "ni", "faciat", "maria", "ac", "terras", "caelumque", "profundum", "quippe", "ferant",
437 				"rapidi", "secum", "verrantque", "per", "auras", "sed", "pater", "omnipotens", "speluncis", "abdidit",
438 				"atris", "hoc", "metuens", "molemque", "et", "montis", "insuper", "altos", "imposuit", "regemque", "dedit",
439 				"qui", "foedere", "certo", "et", "premere", "et", "laxas", "sciret", "dare", "iussus", "habenas", };
440 
441 	private static final String[] DNS1 = new String[] { "corp", "your", "my", "sample", "company", "test", "any" };
442 	private static final String[] DNS2 = new String[] { "com", "org", "com", "gov", "org", "com", "org", "com", "edu" };
443 
444 	private int pick( int n )
445 	{
446 		return _picker.nextInt( n );
447 	}
448 
449 	private String pick( String[] a )
450 	{
451 		return a[pick( a.length )];
452 	}
453 
454 	private String pick( String[] a, int count )
455 	{
456 		if( count <= 0 )
457 			count = 1;
458 		// return "";
459 
460 		int i = pick( a.length );
461 		StringBuffer sb = new StringBuffer( a[i] );
462 		while( count-- > 0 )
463 		{
464 			i += 1;
465 			if( i >= a.length )
466 				i = 0;
467 			sb.append( ' ' );
468 			sb.append( a[i] );
469 		}
470 		return sb.toString();
471 	}
472 
473 	private String pickDigits( int digits )
474 	{
475 		StringBuffer sb = new StringBuffer();
476 		while( digits-- > 0 )
477 			sb.append( Integer.toString( pick( 10 ) ) );
478 		return sb.toString();
479 	}
480 
481 	private int pickLength( SchemaType sType )
482 	{
483 		XmlInteger length = ( XmlInteger ) sType.getFacet( SchemaType.FACET_LENGTH );
484 		if( length != null )
485 			return length.getBigIntegerValue().intValue();
486 		XmlInteger min = ( XmlInteger ) sType.getFacet( SchemaType.FACET_MIN_LENGTH );
487 		XmlInteger max = ( XmlInteger ) sType.getFacet( SchemaType.FACET_MAX_LENGTH );
488 		int minInt, maxInt;
489 		if( min == null )
490 			minInt = 0;
491 		else
492 			minInt = min.getBigIntegerValue().intValue();
493 		if( max == null )
494 			maxInt = Integer.MAX_VALUE;
495 		else
496 			maxInt = max.getBigIntegerValue().intValue();
497 		// We try to keep the length of the array within reasonable limits,
498 		// at least 1 item and at most 3 if possible
499 		if( minInt == 0 && maxInt >= 1 )
500 			minInt = 1;
501 		if( maxInt > minInt + 2 )
502 			maxInt = minInt + 2;
503 		if( maxInt < minInt )
504 			maxInt = minInt;
505 		return minInt + pick( maxInt - minInt );
506 	}
507 
508 	/***
509 	 * Formats a given string to the required length, using the following
510 	 * operations: - append the source string to itself as necessary to pass the
511 	 * minLength; - truncate the result of previous step, if necessary, to keep
512 	 * it within minLength.
513 	 */
514 	private String formatToLength( String s, SchemaType sType )
515 	{
516 		String result = s;
517 		try
518 		{
519 			SimpleValue min = ( SimpleValue ) sType.getFacet( SchemaType.FACET_LENGTH );
520 			if( min == null )
521 				min = ( SimpleValue ) sType.getFacet( SchemaType.FACET_MIN_LENGTH );
522 			if( min != null )
523 			{
524 				int len = min.getIntValue();
525 				while( result.length() < len )
526 					result = result + result;
527 			}
528 			SimpleValue max = ( SimpleValue ) sType.getFacet( SchemaType.FACET_LENGTH );
529 			if( max == null )
530 				max = ( SimpleValue ) sType.getFacet( SchemaType.FACET_MAX_LENGTH );
531 			if( max != null )
532 			{
533 				int len = max.getIntValue();
534 				if( result.length() > len )
535 					result = result.substring( 0, len );
536 			}
537 		}
538 		catch( Exception e ) // intValue can be out of range
539 		{
540 		}
541 		return result;
542 	}
543 
544 	private String formatDecimal( String start, SchemaType sType )
545 	{
546 		BigDecimal result = new BigDecimal( start );
547 		XmlDecimal xmlD;
548 		xmlD = ( XmlDecimal ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
549 		BigDecimal min = xmlD != null ? xmlD.getBigDecimalValue() : null;
550 		xmlD = ( XmlDecimal ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
551 		BigDecimal max = xmlD != null ? xmlD.getBigDecimalValue() : null;
552 		boolean minInclusive = true, maxInclusive = true;
553 		xmlD = ( XmlDecimal ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
554 		if( xmlD != null )
555 		{
556 			BigDecimal minExcl = xmlD.getBigDecimalValue();
557 			if( min == null || min.compareTo( minExcl ) < 0 )
558 			{
559 				min = minExcl;
560 				minInclusive = false;
561 			}
562 		}
563 		xmlD = ( XmlDecimal ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
564 		if( xmlD != null )
565 		{
566 			BigDecimal maxExcl = xmlD.getBigDecimalValue();
567 			if( max == null || max.compareTo( maxExcl ) > 0 )
568 			{
569 				max = maxExcl;
570 				maxInclusive = false;
571 			}
572 		}
573 		xmlD = ( XmlDecimal ) sType.getFacet( SchemaType.FACET_TOTAL_DIGITS );
574 		int totalDigits = -1;
575 		if( xmlD != null )
576 		{
577 			totalDigits = xmlD.getBigDecimalValue().intValue();
578 
579 			StringBuffer sb = new StringBuffer( totalDigits );
580 			for( int i = 0; i < totalDigits; i++ )
581 				sb.append( '9' );
582 			BigDecimal digitsLimit = new BigDecimal( sb.toString() );
583 			if( max != null && max.compareTo( digitsLimit ) > 0 )
584 			{
585 				max = digitsLimit;
586 				maxInclusive = true;
587 			}
588 			digitsLimit = digitsLimit.negate();
589 			if( min != null && min.compareTo( digitsLimit ) < 0 )
590 			{
591 				min = digitsLimit;
592 				minInclusive = true;
593 			}
594 		}
595 
596 		int sigMin = min == null ? 1 : result.compareTo( min );
597 		int sigMax = max == null ? -1 : result.compareTo( max );
598 		boolean minOk = sigMin > 0 || sigMin == 0 && minInclusive;
599 		boolean maxOk = sigMax < 0 || sigMax == 0 && maxInclusive;
600 
601 		// Compute the minimum increment
602 		xmlD = ( XmlDecimal ) sType.getFacet( SchemaType.FACET_FRACTION_DIGITS );
603 		int fractionDigits = -1;
604 		BigDecimal increment;
605 		if( xmlD == null )
606 			increment = new BigDecimal( 1 );
607 		else
608 		{
609 			fractionDigits = xmlD.getBigDecimalValue().intValue();
610 			if( fractionDigits > 0 )
611 			{
612 				StringBuffer sb = new StringBuffer( "0." );
613 				for( int i = 1; i < fractionDigits; i++ )
614 					sb.append( '0' );
615 				sb.append( '1' );
616 				increment = new BigDecimal( sb.toString() );
617 			}
618 			else
619 				increment = new BigDecimal( 1 );
620 		}
621 
622 		if( minOk && maxOk )
623 		{
624 			// OK
625 		}
626 		else if( minOk && !maxOk )
627 		{
628 			// TOO BIG
629 			if( maxInclusive )
630 				result = max;
631 			else
632 				result = max.subtract( increment );
633 		}
634 		else if( !minOk && maxOk )
635 		{
636 			// TOO SMALL
637 			if( minInclusive )
638 				result = min;
639 			else
640 				result = min.add( increment );
641 		}
642 		else
643 		{
644 			// MIN > MAX!!
645 		}
646 
647 		// We have the number
648 		// Adjust the scale according to the totalDigits and fractionDigits
649 		int digits = 0;
650 		BigDecimal ONE = new BigDecimal( BigInteger.ONE );
651 		for( BigDecimal n = result; n.abs().compareTo( ONE ) >= 0; digits++ )
652 			n = n.movePointLeft( 1 );
653 
654 		if( fractionDigits > 0 )
655 			if( totalDigits >= 0 )
656 				result.setScale( Math.max( fractionDigits, totalDigits - digits ) );
657 			else
658 				result.setScale( fractionDigits );
659 		else if( fractionDigits == 0 )
660 			result.setScale( 0 );
661 
662 		return result.toString();
663 	}
664 
665 	private String formatDuration( SchemaType sType )
666 	{
667 		XmlDuration d = ( XmlDuration ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
668 		GDuration minInclusive = null;
669 		if( d != null )
670 			minInclusive = d.getGDurationValue();
671 
672 		d = ( XmlDuration ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
673 		GDuration maxInclusive = null;
674 		if( d != null )
675 			maxInclusive = d.getGDurationValue();
676 
677 		d = ( XmlDuration ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
678 		GDuration minExclusive = null;
679 		if( d != null )
680 			minExclusive = d.getGDurationValue();
681 
682 		d = ( XmlDuration ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
683 		GDuration maxExclusive = null;
684 		if( d != null )
685 			maxExclusive = d.getGDurationValue();
686 
687 		GDurationBuilder gdurb = new GDurationBuilder();
688 		BigInteger min, max;
689 
690 		gdurb.setSecond( pick( 800000 ) );
691 		gdurb.setMonth( pick( 20 ) );
692 
693 		// Years
694 		// Months
695 		// Days
696 		// Hours
697 		// Minutes
698 		// Seconds
699 		// Fractions
700 		if( minInclusive != null )
701 		{
702 			if( gdurb.getYear() < minInclusive.getYear() )
703 				gdurb.setYear( minInclusive.getYear() );
704 			if( gdurb.getMonth() < minInclusive.getMonth() )
705 				gdurb.setMonth( minInclusive.getMonth() );
706 			if( gdurb.getDay() < minInclusive.getDay() )
707 				gdurb.setDay( minInclusive.getDay() );
708 			if( gdurb.getHour() < minInclusive.getHour() )
709 				gdurb.setHour( minInclusive.getHour() );
710 			if( gdurb.getMinute() < minInclusive.getMinute() )
711 				gdurb.setMinute( minInclusive.getMinute() );
712 			if( gdurb.getSecond() < minInclusive.getSecond() )
713 				gdurb.setSecond( minInclusive.getSecond() );
714 			if( gdurb.getFraction().compareTo( minInclusive.getFraction() ) < 0 )
715 				gdurb.setFraction( minInclusive.getFraction() );
716 		}
717 
718 		if( maxInclusive != null )
719 		{
720 			if( gdurb.getYear() > maxInclusive.getYear() )
721 				gdurb.setYear( maxInclusive.getYear() );
722 			if( gdurb.getMonth() > maxInclusive.getMonth() )
723 				gdurb.setMonth( maxInclusive.getMonth() );
724 			if( gdurb.getDay() > maxInclusive.getDay() )
725 				gdurb.setDay( maxInclusive.getDay() );
726 			if( gdurb.getHour() > maxInclusive.getHour() )
727 				gdurb.setHour( maxInclusive.getHour() );
728 			if( gdurb.getMinute() > maxInclusive.getMinute() )
729 				gdurb.setMinute( maxInclusive.getMinute() );
730 			if( gdurb.getSecond() > maxInclusive.getSecond() )
731 				gdurb.setSecond( maxInclusive.getSecond() );
732 			if( gdurb.getFraction().compareTo( maxInclusive.getFraction() ) > 0 )
733 				gdurb.setFraction( maxInclusive.getFraction() );
734 		}
735 
736 		if( minExclusive != null )
737 		{
738 			if( gdurb.getYear() <= minExclusive.getYear() )
739 				gdurb.setYear( minExclusive.getYear() + 1 );
740 			if( gdurb.getMonth() <= minExclusive.getMonth() )
741 				gdurb.setMonth( minExclusive.getMonth() + 1 );
742 			if( gdurb.getDay() <= minExclusive.getDay() )
743 				gdurb.setDay( minExclusive.getDay() + 1 );
744 			if( gdurb.getHour() <= minExclusive.getHour() )
745 				gdurb.setHour( minExclusive.getHour() + 1 );
746 			if( gdurb.getMinute() <= minExclusive.getMinute() )
747 				gdurb.setMinute( minExclusive.getMinute() + 1 );
748 			if( gdurb.getSecond() <= minExclusive.getSecond() )
749 				gdurb.setSecond( minExclusive.getSecond() + 1 );
750 			if( gdurb.getFraction().compareTo( minExclusive.getFraction() ) <= 0 )
751 				gdurb.setFraction( minExclusive.getFraction().add( new BigDecimal( 0.001 ) ) );
752 		}
753 
754 		if( maxExclusive != null )
755 		{
756 			if( gdurb.getYear() > maxExclusive.getYear() )
757 				gdurb.setYear( maxExclusive.getYear() );
758 			if( gdurb.getMonth() > maxExclusive.getMonth() )
759 				gdurb.setMonth( maxExclusive.getMonth() );
760 			if( gdurb.getDay() > maxExclusive.getDay() )
761 				gdurb.setDay( maxExclusive.getDay() );
762 			if( gdurb.getHour() > maxExclusive.getHour() )
763 				gdurb.setHour( maxExclusive.getHour() );
764 			if( gdurb.getMinute() > maxExclusive.getMinute() )
765 				gdurb.setMinute( maxExclusive.getMinute() );
766 			if( gdurb.getSecond() > maxExclusive.getSecond() )
767 				gdurb.setSecond( maxExclusive.getSecond() );
768 			if( gdurb.getFraction().compareTo( maxExclusive.getFraction() ) > 0 )
769 				gdurb.setFraction( maxExclusive.getFraction() );
770 		}
771 
772 		gdurb.normalize();
773 		return gdurb.toString();
774 	}
775 
776 	private String formatDate( SchemaType sType )
777 	{
778 		GDateBuilder gdateb = new GDateBuilder( new Date( 1000L * pick( 365 * 24 * 60 * 60 ) + ( 30L + pick( 20 ) ) * 365
779 					* 24 * 60 * 60 * 1000 ) );
780 		GDate min = null, max = null;
781 		GDate temp;
782 
783 		// Find the min and the max according to the type
784 		switch( sType.getPrimitiveType().getBuiltinTypeCode() )
785 		{
786 		case SchemaType.BTC_DATE_TIME:
787 		{
788 			XmlDateTime x = ( XmlDateTime ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
789 			if( x != null )
790 				min = x.getGDateValue();
791 			x = ( XmlDateTime ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
792 			if( x != null )
793 				if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
794 					min = x.getGDateValue();
795 
796 			x = ( XmlDateTime ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
797 			if( x != null )
798 				max = x.getGDateValue();
799 			x = ( XmlDateTime ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
800 			if( x != null )
801 				if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
802 					max = x.getGDateValue();
803 			break;
804 		}
805 		case SchemaType.BTC_TIME:
806 		{
807 			XmlTime x = ( XmlTime ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
808 			if( x != null )
809 				min = x.getGDateValue();
810 			x = ( XmlTime ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
811 			if( x != null )
812 				if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
813 					min = x.getGDateValue();
814 
815 			x = ( XmlTime ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
816 			if( x != null )
817 				max = x.getGDateValue();
818 			x = ( XmlTime ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
819 			if( x != null )
820 				if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
821 					max = x.getGDateValue();
822 			break;
823 		}
824 		case SchemaType.BTC_DATE:
825 		{
826 			XmlDate x = ( XmlDate ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
827 			if( x != null )
828 				min = x.getGDateValue();
829 			x = ( XmlDate ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
830 			if( x != null )
831 				if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
832 					min = x.getGDateValue();
833 
834 			x = ( XmlDate ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
835 			if( x != null )
836 				max = x.getGDateValue();
837 			x = ( XmlDate ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
838 			if( x != null )
839 				if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
840 					max = x.getGDateValue();
841 			break;
842 		}
843 		case SchemaType.BTC_G_YEAR_MONTH:
844 		{
845 			XmlGYearMonth x = ( XmlGYearMonth ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
846 			if( x != null )
847 				min = x.getGDateValue();
848 			x = ( XmlGYearMonth ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
849 			if( x != null )
850 				if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
851 					min = x.getGDateValue();
852 
853 			x = ( XmlGYearMonth ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
854 			if( x != null )
855 				max = x.getGDateValue();
856 			x = ( XmlGYearMonth ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
857 			if( x != null )
858 				if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
859 					max = x.getGDateValue();
860 			break;
861 		}
862 		case SchemaType.BTC_G_YEAR:
863 		{
864 			XmlGYear x = ( XmlGYear ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
865 			if( x != null )
866 				min = x.getGDateValue();
867 			x = ( XmlGYear ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
868 			if( x != null )
869 				if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
870 					min = x.getGDateValue();
871 
872 			x = ( XmlGYear ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
873 			if( x != null )
874 				max = x.getGDateValue();
875 			x = ( XmlGYear ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
876 			if( x != null )
877 				if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
878 					max = x.getGDateValue();
879 			break;
880 		}
881 		case SchemaType.BTC_G_MONTH_DAY:
882 		{
883 			XmlGMonthDay x = ( XmlGMonthDay ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
884 			if( x != null )
885 				min = x.getGDateValue();
886 			x = ( XmlGMonthDay ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
887 			if( x != null )
888 				if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
889 					min = x.getGDateValue();
890 
891 			x = ( XmlGMonthDay ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
892 			if( x != null )
893 				max = x.getGDateValue();
894 			x = ( XmlGMonthDay ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
895 			if( x != null )
896 				if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
897 					max = x.getGDateValue();
898 			break;
899 		}
900 		case SchemaType.BTC_G_DAY:
901 		{
902 			XmlGDay x = ( XmlGDay ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
903 			if( x != null )
904 				min = x.getGDateValue();
905 			x = ( XmlGDay ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
906 			if( x != null )
907 				if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
908 					min = x.getGDateValue();
909 
910 			x = ( XmlGDay ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
911 			if( x != null )
912 				max = x.getGDateValue();
913 			x = ( XmlGDay ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
914 			if( x != null )
915 				if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
916 					max = x.getGDateValue();
917 			break;
918 		}
919 		case SchemaType.BTC_G_MONTH:
920 		{
921 			XmlGMonth x = ( XmlGMonth ) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
922 			if( x != null )
923 				min = x.getGDateValue();
924 			x = ( XmlGMonth ) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
925 			if( x != null )
926 				if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
927 					min = x.getGDateValue();
928 
929 			x = ( XmlGMonth ) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
930 			if( x != null )
931 				max = x.getGDateValue();
932 			x = ( XmlGMonth ) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
933 			if( x != null )
934 				if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
935 					max = x.getGDateValue();
936 			break;
937 		}
938 		}
939 
940 		if( min != null && max == null )
941 		{
942 			if( min.compareToGDate( gdateb ) >= 0 )
943 			{
944 				// Reset the date to min + (1-8) hours
945 				Calendar c = gdateb.getCalendar();
946 				c.add( Calendar.HOUR_OF_DAY, pick( 8 ) );
947 				gdateb = new GDateBuilder( c );
948 			}
949 		}
950 		else if( min == null && max != null )
951 		{
952 			if( max.compareToGDate( gdateb ) <= 0 )
953 			{
954 				// Reset the date to max - (1-8) hours
955 				Calendar c = gdateb.getCalendar();
956 				c.add( Calendar.HOUR_OF_DAY, 0 - pick( 8 ) );
957 				gdateb = new GDateBuilder( c );
958 			}
959 		}
960 		else if( min != null && max != null )
961 		{
962 			if( min.compareToGDate( gdateb ) >= 0 || max.compareToGDate( gdateb ) <= 0 )
963 			{
964 				// Find a date between the two
965 				Calendar c = min.getCalendar();
966 				Calendar cmax = max.getCalendar();
967 				c.add( Calendar.HOUR_OF_DAY, 1 );
968 				if( c.after( cmax ) )
969 				{
970 					c.add( Calendar.HOUR_OF_DAY, -1 );
971 					c.add( Calendar.MINUTE, 1 );
972 					if( c.after( cmax ) )
973 					{
974 						c.add( Calendar.MINUTE, -1 );
975 						c.add( Calendar.SECOND, 1 );
976 						if( c.after( cmax ) )
977 						{
978 							c.add( Calendar.SECOND, -1 );
979 							c.add( Calendar.MILLISECOND, 1 );
980 							if( c.after( cmax ) )
981 								c.add( Calendar.MILLISECOND, -1 );
982 						}
983 					}
984 				}
985 				gdateb = new GDateBuilder( c );
986 			}
987 		}
988 
989 		gdateb.setBuiltinTypeCode( sType.getPrimitiveType().getBuiltinTypeCode() );
990 		if( pick( 2 ) == 0 )
991 			gdateb.clearTimeZone();
992 		return gdateb.toString();
993 	}
994 
995 	private SchemaType closestBuiltin( SchemaType sType )
996 	{
997 		while( !sType.isBuiltinType() )
998 			sType = sType.getBaseType();
999 		return sType;
1000 	}
1001 
1002 	/***
1003 	 * Cracks a combined QName of the form URL:localname
1004 	 */
1005 	public static QName crackQName( String qName )
1006 	{
1007 		String ns;
1008 		String name;
1009 
1010 		int index = qName.lastIndexOf( ':' );
1011 		if( index >= 0 )
1012 		{
1013 			ns = qName.substring( 0, index );
1014 			name = qName.substring( index + 1 );
1015 		}
1016 		else
1017 		{
1018 			ns = "";
1019 			name = qName;
1020 		}
1021 
1022 		return new QName( ns, name );
1023 	}
1024 
1025 	/***
1026 	 * Cursor position: Before this call: <outer><foo/>^</outer> (cursor at the ^)
1027 	 * After this call: <<outer><foo/><bar/>som text<etc/>^</outer>
1028 	 */
1029 	private void processParticle( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1030 	{
1031 		int loop = determineMinMaxForSample( sp, xmlc );
1032 
1033 		while( loop-- > 0 )
1034 		{
1035 			switch( sp.getParticleType() )
1036 			{
1037 			case ( SchemaParticle.ELEMENT ):
1038 				processElement( sp, xmlc, mixed );
1039 				break;
1040 			case ( SchemaParticle.SEQUENCE ):
1041 				processSequence( sp, xmlc, mixed );
1042 				break;
1043 			case ( SchemaParticle.CHOICE ):
1044 				processChoice( sp, xmlc, mixed );
1045 				break;
1046 			case ( SchemaParticle.ALL ):
1047 				processAll( sp, xmlc, mixed );
1048 				break;
1049 			case ( SchemaParticle.WILDCARD ):
1050 				processWildCard( sp, xmlc, mixed );
1051 				break;
1052 			default:
1053 				// throw new Exception("No Match on Schema Particle Type: " +
1054 				// String.valueOf(sp.getParticleType()));
1055 			}
1056 		}
1057 	}
1058 
1059 	private int determineMinMaxForSample( SchemaParticle sp, XmlCursor xmlc )
1060 	{
1061 		int minOccurs = sp.getIntMinOccurs();
1062 		int maxOccurs = sp.getIntMaxOccurs();
1063 
1064 		if( minOccurs == maxOccurs )
1065 			return minOccurs;
1066 
1067 		if( minOccurs == 0 && ignoreOptional )
1068 			return 0;
1069 
1070 		int result = minOccurs;
1071 		if( result == 0 )
1072 			result = 1;
1073 
1074 		if( sp.getParticleType() != SchemaParticle.ELEMENT )
1075 			return result;
1076 
1077 		// it probably only makes sense to put comments in front of individual
1078 		// elements that repeat
1079 
1080 		if( !_skipComments )
1081 		{
1082 			if( sp.getMaxOccurs() == null )
1083 			{
1084 				// xmlc.insertComment("The next " + getItemNameOrType(sp, xmlc) + " may
1085 				// be repeated " + minOccurs + " or more times");
1086 				if( minOccurs == 0 )
1087 					xmlc.insertComment( "Zero or more repetitions:" );
1088 				else
1089 					xmlc.insertComment( minOccurs + " or more repetitions:" );
1090 			}
1091 			else if( sp.getIntMaxOccurs() > 1 )
1092 			{
1093 				xmlc.insertComment( minOccurs + " to " + String.valueOf( sp.getMaxOccurs() ) + " repetitions:" );
1094 			}
1095 			else
1096 			{
1097 				xmlc.insertComment( "Optional:" );
1098 			}
1099 		}
1100 		
1101 		return result;
1102 	}
1103 
1104 	/*
1105 	 * Return a name for the element or the particle type to use in the comment
1106 	 * for minoccurs, max occurs
1107 	 */
1108 	private String getItemNameOrType( SchemaParticle sp, XmlCursor xmlc )
1109 	{
1110 		String elementOrTypeName = null;
1111 		if( sp.getParticleType() == SchemaParticle.ELEMENT )
1112 		{
1113 			elementOrTypeName = "Element (" + sp.getName().getLocalPart() + ")";
1114 		}
1115 		else
1116 		{
1117 			elementOrTypeName = printParticleType( sp.getParticleType() );
1118 		}
1119 		return elementOrTypeName;
1120 	}
1121 
1122 	private void processElement( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1123 	{
1124 		// cast as schema local element
1125 		SchemaLocalElement element = ( SchemaLocalElement ) sp;
1126 
1127 		// Add comment about type
1128 		addElementTypeAndRestricionsComment( element, xmlc );
1129 
1130 		// / ^ -> <elemenname></elem>^
1131 		if( _soapEnc )
1132 			xmlc.insertElement( element.getName().getLocalPart() ); // soap
1133 																						// encoded?
1134 																						// drop
1135 																						// namespaces.
1136 		else
1137 			xmlc.insertElement( element.getName().getLocalPart(), element.getName().getNamespaceURI() );
1138 		// / -> <elem>^</elem>
1139 		// processAttributes( sp.getType(), xmlc );
1140 
1141 		xmlc.toPrevToken();
1142 		// -> <elem>stuff^</elem>
1143 
1144 		if( sp.isDefault() )
1145 			xmlc.insertChars( sp.getDefaultText() );
1146 		else
1147 			createSampleForType( element.getType(), xmlc );
1148 		// -> <elem>stuff</elem>^
1149 		xmlc.toNextToken();
1150 
1151 	}
1152 
1153 	private void moveToken( int numToMove, XmlCursor xmlc )
1154 	{
1155 		for( int i = 0; i < Math.abs( numToMove ); i++ )
1156 		{
1157 			if( numToMove < 0 )
1158 			{
1159 				xmlc.toPrevToken();
1160 			}
1161 			else
1162 			{
1163 				xmlc.toNextToken();
1164 			}
1165 		}
1166 	}
1167 
1168 	private static final String formatQName( XmlCursor xmlc, QName qName )
1169 	{
1170 		XmlCursor parent = xmlc.newCursor();
1171 		parent.toParent();
1172 		String prefix = parent.prefixForNamespace( qName.getNamespaceURI() );
1173 		parent.dispose();
1174 		String name;
1175 		if( prefix == null || prefix.length() == 0 )
1176 			name = qName.getLocalPart();
1177 		else
1178 			name = prefix + ":" + qName.getLocalPart();
1179 		return name;
1180 	}
1181 
1182 	private static final QName HREF = new QName( "href" );
1183 	private static final QName ID = new QName( "id" );
1184 	public static final QName XSI_TYPE = new QName( "http://www.w3.org/2001/XMLSchema-instance", "type" );
1185 	public static final QName ENC_ARRAYTYPE = new QName( "http://schemas.xmlsoap.org/soap/encoding/", "arrayType" );
1186 	private static final QName ENC_OFFSET = new QName( "http://schemas.xmlsoap.org/soap/encoding/", "offset" );
1187 
1188 	public static final Set<QName> SKIPPED_SOAP_ATTRS = new HashSet<QName>( Arrays.asList( new QName[] { HREF, ID,
1189 				ENC_OFFSET } ) );
1190 
1191 	private void processAttributes( SchemaType stype, XmlCursor xmlc )
1192 	{
1193 		if( _soapEnc )
1194 		{
1195 			QName typeName = stype.getName();
1196 			if( typeName != null )
1197 			{
1198 				xmlc.insertAttributeWithValue( XSI_TYPE, formatQName( xmlc, typeName ) );
1199 			}
1200 		}
1201 
1202 		SchemaProperty[] attrProps = stype.getAttributeProperties();
1203 		for( int i = 0; i < attrProps.length; i++ )
1204 		{
1205 			SchemaProperty attr = attrProps[i];
1206 
1207 			if( attr.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "contentType" ) ) )
1208 			{
1209 				xmlc.insertAttributeWithValue( attr.getName(), "application/?" );
1210 				continue;
1211 			}
1212 
1213 			if( _soapEnc )
1214 			{
1215 				if( SKIPPED_SOAP_ATTRS.contains( attr.getName() ) )
1216 					continue;
1217 				if( ENC_ARRAYTYPE.equals( attr.getName() ) )
1218 				{
1219 					SOAPArrayType arrayType = ( ( SchemaWSDLArrayType ) stype.getAttributeModel().getAttribute(
1220 								attr.getName() ) ).getWSDLArrayType();
1221 					if( arrayType != null )
1222 						xmlc.insertAttributeWithValue( attr.getName(), formatQName( xmlc, arrayType.getQName() )
1223 									+ arrayType.soap11DimensionString() );
1224 					continue;
1225 				}
1226 			}
1227 			String defaultValue = attr.getDefaultText();
1228 			xmlc.insertAttributeWithValue( attr.getName(), defaultValue == null ? sampleDataForSimpleType( attr.getType() )
1229 						: defaultValue );
1230 		}
1231 	}
1232 
1233 	private void processSequence( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1234 	{
1235 		SchemaParticle[] spc = sp.getParticleChildren();
1236 		for( int i = 0; i < spc.length; i++ )
1237 		{
1238 			// / <parent>maybestuff^</parent>
1239 			processParticle( spc[i], xmlc, mixed );
1240 			// <parent>maybestuff...morestuff^</parent>
1241 			if( mixed && i < spc.length - 1 )
1242 				xmlc.insertChars( pick( WORDS ) );
1243 		}
1244 	}
1245 
1246 	private void processChoice( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1247 	{
1248 		SchemaParticle[] spc = sp.getParticleChildren();
1249 		if( !_skipComments )
1250 			xmlc.insertComment( "You have a CHOICE of the next " + String.valueOf( spc.length ) + " items at this level" );
1251 		
1252 		for( int i = 0; i < spc.length; i++ )
1253 		{
1254 			processParticle( spc[i], xmlc, mixed );
1255 		}
1256 	}
1257 
1258 	private void processAll( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1259 	{
1260 		SchemaParticle[] spc = sp.getParticleChildren();
1261 		if( !_skipComments )
1262 			xmlc.insertComment( "You may enter the following " + String.valueOf( spc.length ) + " items in any order" );
1263 		
1264 		for( int i = 0; i < spc.length; i++ )
1265 		{
1266 			processParticle( spc[i], xmlc, mixed );
1267 			if( mixed && i < spc.length - 1 )
1268 				xmlc.insertChars( pick( WORDS ) );
1269 		}
1270 	}
1271 
1272 	private void processWildCard( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1273 	{
1274 		if( !_skipComments )
1275 			xmlc.insertComment( "You may enter ANY elements at this point" );
1276 		// xmlc.insertElement("AnyElement");
1277 	}
1278 
1279 	/***
1280 	 * This method will get the base type for the schema type
1281 	 */
1282 
1283 	private static QName getClosestName( SchemaType sType )
1284 	{
1285 		while( sType.getName() == null )
1286 			sType = sType.getBaseType();
1287 
1288 		return sType.getName();
1289 	}
1290 
1291 	private String printParticleType( int particleType )
1292 	{
1293 		StringBuffer returnParticleType = new StringBuffer();
1294 		returnParticleType.append( "Schema Particle Type: " );
1295 
1296 		switch( particleType )
1297 		{
1298 		case SchemaParticle.ALL:
1299 			returnParticleType.append( "ALL\n" );
1300 			break;
1301 		case SchemaParticle.CHOICE:
1302 			returnParticleType.append( "CHOICE\n" );
1303 			break;
1304 		case SchemaParticle.ELEMENT:
1305 			returnParticleType.append( "ELEMENT\n" );
1306 			break;
1307 		case SchemaParticle.SEQUENCE:
1308 			returnParticleType.append( "SEQUENCE\n" );
1309 			break;
1310 		case SchemaParticle.WILDCARD:
1311 			returnParticleType.append( "WILDCARD\n" );
1312 			break;
1313 		default:
1314 			returnParticleType.append( "Schema Particle Type Unknown" );
1315 			break;
1316 		}
1317 
1318 		return returnParticleType.toString();
1319 	}
1320 
1321 	private ArrayList<SchemaType> _typeStack = new ArrayList<SchemaType>();
1322 
1323 	public boolean isIgnoreOptional()
1324 	{
1325 		return ignoreOptional;
1326 	}
1327 
1328 	public void setIgnoreOptional( boolean ignoreOptional )
1329 	{
1330 		this.ignoreOptional = ignoreOptional;
1331 	}
1332 
1333 	private void addElementTypeAndRestricionsComment( SchemaLocalElement element, XmlCursor xmlc )
1334 	{
1335 
1336 		SchemaType type = element.getType();
1337 		if( _typeComment && ( type != null && type.isSimpleType() ) )
1338 		{
1339 			String info = "";
1340 
1341 			XmlAnySimpleType[] values = type.getEnumerationValues();
1342 			if( values != null && values.length > 0 )
1343 			{
1344 				info = " - enumeration: [";
1345 				for( int c = 0; c < values.length; c++ )
1346 				{
1347 					if( c > 0 )
1348 						info += ",";
1349 
1350 					info += values[c].getStringValue();
1351 				}
1352 
1353 				info += "]";
1354 			}
1355 
1356 			if( type.isAnonymousType() )
1357 				xmlc.insertComment( "anonymous type" + info );
1358 			else
1359 				xmlc.insertComment( "type: " + type.getName().getLocalPart() + info );
1360 		}
1361 	}
1362 
1363 }