[194698] - structured XSD annotations are mangled by formatter
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/DefaultXMLPartitionFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/DefaultXMLPartitionFormatter.java
index 55d4867..a3785cf 100644
--- a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/DefaultXMLPartitionFormatter.java
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/DefaultXMLPartitionFormatter.java
@@ -59,17 +59,32 @@
 	}
 
 	static private final String PRESERVE = "preserve";//$NON-NLS-1$
+	static private final String COLLAPSE = "collapse";//$NON-NLS-1$
+	static private final String REPLACE = "replace";//$NON-NLS-1$
 	static private final String PRESERVE_QUOTED = "\"preserve\"";//$NON-NLS-1$
 	static private final String XML_SPACE = "xml:space";//$NON-NLS-1$
 	static private final String XSL_NAMESPACE = "http://www.w3.org/1999/XSL/Transform"; //$NON-NLS-1$
 	static private final String XSL_ATTRIBUTE = "attribute"; //$NON-NLS-1$
 	static private final String XSL_TEXT = "text"; //$NON-NLS-1$
 	static private final String SPACE = " "; //$NON-NLS-1$
-	static private final String STRING = "string"; //$NON-NLS-1$
+	static private final String PROPERTY_WHITESPACE_FACET = "org.eclipse.wst.xsd.cm.properties/whitespace"; //$NON-NLS-1$
 
 	private XMLFormattingPreferences fPreferences = null;
 	private IProgressMonitor fProgressMonitor;
 
+	private int replaceSpaces(TextEdit textEdit, int spaceStartOffset, int availableLineWidth, String whitespaceRun) {
+		StringBuffer buff = new StringBuffer(whitespaceRun);
+		for(int i = 0; i < buff.length(); i++) {
+			buff.setCharAt(i, ' '); //$NON-NLS-1$
+		}
+		String replacementString = buff.toString();
+		if (!replacementString.equals(whitespaceRun)) {
+			ReplaceEdit replaceEdit = new ReplaceEdit(spaceStartOffset, whitespaceRun.length(), replacementString);
+			textEdit.addChild(replaceEdit);
+		}
+		return availableLineWidth;
+	}
+	
 	private int collapseSpaces(TextEdit textEdit, int spaceStartOffset, int availableLineWidth, String whitespaceRun) {
 		// prefer to use use existing whitespace
 		int existingWhitespaceOffset = whitespaceRun.indexOf(' ');
@@ -700,7 +715,15 @@
 					}
 					else {
 						// just collapse spaces, but adjust for any indenting that may result from preserving line delimiters
-						availableLineWidth = collapseAndIndent(textEdit, startOffset, availableLineWidth, indentLevel, whitespaceRun, currentRegion);
+						if (whitespaceStart == 0 && whitespaceMode == XMLFormattingConstraints.IGNOREANDTRIM) {
+							// if ignore, trim
+							DeleteEdit deleteTrailing = new DeleteEdit(startOffset, whitespaceRun.length());
+							textEdit.addChild(deleteTrailing);
+						}
+						else if(whitespaceMode == XMLFormattingConstraints.REPLACE)
+							availableLineWidth = replaceSpaces(textEdit, startOffset, availableLineWidth, whitespaceRun);
+						else
+							availableLineWidth = collapseAndIndent(textEdit, startOffset, availableLineWidth, indentLevel, whitespaceRun, currentRegion);
 					}
 
 					fullTextOffset += characterRunLength;
@@ -708,7 +731,14 @@
 				else {
 					// handle trailing whitespace
 					int whitespaceOffset = currentRegion.getStartOffset() + whitespaceStart;
-					if(getFormattingPreferences().getClearAllBlankLines()) {
+					if (whitespaceMode == XMLFormattingConstraints.REPLACE)
+						availableLineWidth = replaceSpaces(textEdit, whitespaceOffset, availableLineWidth, whitespaceRun);
+					else if (whitespaceMode == XMLFormattingConstraints.IGNOREANDTRIM) {
+						// always trim
+						DeleteEdit deleteTrailing = new DeleteEdit(whitespaceOffset, whitespaceRun.length());
+						textEdit.addChild(deleteTrailing);
+					}
+					else if(getFormattingPreferences().getClearAllBlankLines()) {
 						if (whitespaceMode == XMLFormattingConstraints.IGNORE) {
 							// if ignore, trim
 							DeleteEdit deleteTrailing = new DeleteEdit(whitespaceOffset, whitespaceRun.length());
@@ -731,7 +761,7 @@
 					// indent if word is too long or forcing initial
 					// indent
 					availableLineWidth = availableLineWidth - characterRunLength;
-					if (whitespaceMode == XMLFormattingConstraints.IGNORE && (forceInitialIndent || (availableLineWidth <= 0))) {
+					if ((whitespaceMode == XMLFormattingConstraints.IGNORE || whitespaceMode == XMLFormattingConstraints.IGNOREANDTRIM) && (forceInitialIndent || (availableLineWidth <= 0))) {
 						// indent if not already indented
 						availableLineWidth = indentIfNotAlreadyIndented(textEdit, currentRegion, indentLevel, currentRegion.getStartOffset(), whitespaceRun);
 						// remember to subtract word length
@@ -771,8 +801,8 @@
 
 				if (indentStrategy == XMLFormattingConstraints.INLINE) {
 					// if was inlining, need to check if out of available line
-					// width
-					if (availableLineWidth < 0) {
+					// width - Whitespace may have been corrected in the text content
+					if (availableLineWidth < 0 && whitespaceStrategy == XMLFormattingConstraints.IGNORE) {
 						// need to deindent if possible
 						int lineWidth = indentIfPossible(textEdit, constraints, currentDocumentRegion, previousDocumentRegion, whitespaceStrategy, indentStrategy, false);
 						// update available line width
@@ -1190,7 +1220,7 @@
 					String existingDelimiters = extractLineDelimiters(whitespaceRun, currentRegion);
 					if(existingDelimiters != null && existingDelimiters.length() > 0) {
 						String formatted = existingDelimiters + indentString;
-						// Don't perform a replace if the formatted string is the same as the exisiting whitespaceRun
+						// Don't perform a replace if the formatted string is the same as the existing whitespaceRun
 						if(!formatted.equals(whitespaceRun))
 							indentation = new ReplaceEdit(indentStartOffset, whitespaceRun.length(), formatted);
 					}
@@ -1234,7 +1264,7 @@
 		String previousRegionFullText = null;
 		String previousRegionType = null;
 
-		if (whitespaceStrategy == XMLFormattingConstraints.IGNORE) {
+		if ((whitespaceStrategy == XMLFormattingConstraints.IGNORE) || whitespaceStrategy == XMLFormattingConstraints.IGNOREANDTRIM) {
 			// if ignoring, need to check if previous region was cdata
 			previousRegionType = previousDocumentRegion.getType();
 			if (previousRegionType == DOMRegionContext.XML_CDATA_TEXT)
@@ -1496,7 +1526,20 @@
 							// follow whitespace strategy preference for
 							// pcdata content
 							int contentType = elementDeclaration.getContentType();
-							if (contentType == CMElementDeclaration.PCDATA && parentConstraints != null && !XMLFormattingConstraints.PRESERVE.equals(parentConstraints.getWhitespaceStrategy())) {
+							
+							String facetValue = null;
+							if(elementDeclaration.getDataType() != null)
+								facetValue = (String) elementDeclaration.getDataType().getProperty(PROPERTY_WHITESPACE_FACET);
+							if(facetValue != null) {
+								if(PRESERVE.equals(facetValue))
+									childConstraints.setWhitespaceStrategy(XMLFormattingConstraints.PRESERVE);
+								// For XSD types, "collapse" corresponds to the IGNOREANDTRIM strategy
+								else if(COLLAPSE.equals(facetValue))
+									childConstraints.setWhitespaceStrategy(XMLFormattingConstraints.IGNOREANDTRIM);
+								else if(REPLACE.equals(facetValue))
+									childConstraints.setWhitespaceStrategy(XMLFormattingConstraints.REPLACE);
+							}
+							else if (contentType == CMElementDeclaration.PCDATA && parentConstraints != null && !XMLFormattingConstraints.PRESERVE.equals(parentConstraints.getWhitespaceStrategy())) {
 								childConstraints.setWhitespaceStrategy(preferences.getPCDataWhitespaceStrategy());
 							}
 							else if (contentType == CMElementDeclaration.ELEMENT && parentConstraints != null && !XMLFormattingConstraints.PRESERVE.equals(parentConstraints.getWhitespaceStrategy())) {
@@ -1506,58 +1549,53 @@
 								childConstraints.setIsIndentStrategyAHint(true);
 							}
 							else {
-								CMDataType dataType = elementDeclaration.getDataType();
-								if (dataType != null && STRING.equals(dataType.getDataTypeName()))
-									childConstraints.setWhitespaceStrategy(XMLFormattingConstraints.PRESERVE);
-								else {
-									// look for xml:space in content model
-									CMNamedNodeMap cmAttributes = elementDeclaration.getAttributes();
+								// look for xml:space in content model
+								CMNamedNodeMap cmAttributes = elementDeclaration.getAttributes();
 
-									CMNamedNodeMapImpl allAttributes = new CMNamedNodeMapImpl(cmAttributes);
-										List nodes = ModelQueryUtil.getModelQuery(currentNode.getOwnerDocument()).getAvailableContent((Element) currentNode, elementDeclaration, ModelQuery.INCLUDE_ATTRIBUTES);
-										for (int k = 0; k < nodes.size(); k++) {
-											CMNode cmnode = (CMNode) nodes.get(k);
-											if (cmnode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) {
-												allAttributes.put(cmnode);
-											}
-										}
-									cmAttributes = allAttributes;
-									
-									// Check implied values from the DTD way.
-									CMAttributeDeclaration attributeDeclaration = (CMAttributeDeclaration) cmAttributes.getNamedItem(XML_SPACE);
-									if (attributeDeclaration != null) {
-										// CMAttributeDeclaration found, check
-										// it
-										// out.
-										
-										//BUG214516/196544 - Fixed NPE that was caused by an attr having
-										// a null attr type
-										String defaultValue = null;
-										CMDataType attrType = attributeDeclaration.getAttrType();
-										if(attrType != null) {
-											if((attrType.getImpliedValueKind() != CMDataType.IMPLIED_VALUE_NONE) && attrType.getImpliedValue() != null)
-												defaultValue = attrType.getImpliedValue();
-											else if ((attrType.getEnumeratedValues() != null) && (attrType.getEnumeratedValues().length > 0)) {
-												defaultValue = attrType.getEnumeratedValues()[0];
-											}
-										}
-										
-										// xml:space="preserve" means preserve
-										// space,
-										// everything else means back to
-										// default.
-										if(PRESERVE.equals(defaultValue))
-											childConstraints.setWhitespaceStrategy(XMLFormattingConstraints.PRESERVE);
-										else
-											childConstraints.setWhitespaceStrategy(XMLFormattingConstraints.DEFAULT);
+								CMNamedNodeMapImpl allAttributes = new CMNamedNodeMapImpl(cmAttributes);
+								List nodes = ModelQueryUtil.getModelQuery(currentNode.getOwnerDocument()).getAvailableContent((Element) currentNode, elementDeclaration, ModelQuery.INCLUDE_ATTRIBUTES);
+								for (int k = 0; k < nodes.size(); k++) {
+									CMNode cmnode = (CMNode) nodes.get(k);
+									if (cmnode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) {
+										allAttributes.put(cmnode);
 									}
-									// If the node has no attributes, inherit the parents whitespace strategy
-									else {
-										if(parentConstraints != null)
-											childConstraints.setWhitespaceStrategy(parentConstraints.getWhitespaceStrategy());
-										else
-											childConstraints.setWhitespaceStrategy(null);
+								}
+								cmAttributes = allAttributes;
+
+								// Check implied values from the DTD way.
+								CMAttributeDeclaration attributeDeclaration = (CMAttributeDeclaration) cmAttributes.getNamedItem(XML_SPACE);
+								if (attributeDeclaration != null) {
+									// CMAttributeDeclaration found, check
+									// it
+									// out.
+
+									//BUG214516/196544 - Fixed NPE that was caused by an attr having
+									// a null attr type
+									String defaultValue = null;
+									CMDataType attrType = attributeDeclaration.getAttrType();
+									if (attrType != null) {
+										if ((attrType.getImpliedValueKind() != CMDataType.IMPLIED_VALUE_NONE) && attrType.getImpliedValue() != null)
+											defaultValue = attrType.getImpliedValue();
+										else if ((attrType.getEnumeratedValues() != null) && (attrType.getEnumeratedValues().length > 0)) {
+											defaultValue = attrType.getEnumeratedValues()[0];
+										}
 									}
+
+									// xml:space="preserve" means preserve
+									// space,
+									// everything else means back to
+									// default.
+									if (PRESERVE.equals(defaultValue))
+										childConstraints.setWhitespaceStrategy(XMLFormattingConstraints.PRESERVE);
+									else
+										childConstraints.setWhitespaceStrategy(XMLFormattingConstraints.DEFAULT);
+								}
+								// If the node has no attributes, inherit the parents whitespace strategy
+								else {
+									if (parentConstraints != null)
+										childConstraints.setWhitespaceStrategy(parentConstraints.getWhitespaceStrategy());
+									else
+										childConstraints.setWhitespaceStrategy(null);
 								}
 							}
 						}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/XMLFormattingConstraints.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/XMLFormattingConstraints.java
index 6bf3763..fa2a53b 100644
--- a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/XMLFormattingConstraints.java
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/formatter/XMLFormattingConstraints.java
@@ -15,8 +15,10 @@
 	public final static String PRESERVE = "PRESERVE"; //$NON-NLS-1$
 	public final static String COLLAPSE = "COLLAPSE"; //$NON-NLS-1$
 	public final static String IGNORE = "IGNORE"; //$NON-NLS-1$
+	public final static String IGNOREANDTRIM = "IGNOREANDTRIM"; //$NON-NLS-1$
 	public final static String DEFAULT = "DEFAULT"; //$NON-NLS-1$
-
+	public final static String REPLACE = "REPLACE"; //$NON-NLS-1$
+	
 	public final static String INDENT = "INDENT"; //$NON-NLS-1$
 	public final static String NEW_LINE = "NEW_LINE"; //$NON-NLS-1$
 	public final static String INLINE = "INLINE"; //$NON-NLS-1$
diff --git a/bundles/org.eclipse.wst.xsd.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.xsd.core/META-INF/MANIFEST.MF
index 50b92c1..f19d6bc 100644
--- a/bundles/org.eclipse.wst.xsd.core/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.wst.xsd.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %_UI_PLUGIN_NAME
 Bundle-SymbolicName: org.eclipse.wst.xsd.core; singleton:=true
-Bundle-Version: 1.1.300.qualifier
+Bundle-Version: 1.1.301.qualifier
 Bundle-Activator: org.eclipse.wst.xsd.core.internal.XSDCorePlugin
 Bundle-Vendor: %Bundle-Vendor.0
 Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.wst.xsd.core/src-contentmodel/org/eclipse/wst/xsd/contentmodel/internal/XSDImpl.java b/bundles/org.eclipse.wst.xsd.core/src-contentmodel/org/eclipse/wst/xsd/contentmodel/internal/XSDImpl.java
index a58ffa7..af6087c 100644
--- a/bundles/org.eclipse.wst.xsd.core/src-contentmodel/org/eclipse/wst/xsd/contentmodel/internal/XSDImpl.java
+++ b/bundles/org.eclipse.wst.xsd.core/src-contentmodel/org/eclipse/wst/xsd/contentmodel/internal/XSDImpl.java
@@ -133,6 +133,7 @@
   public static final String PROPERTY_SUBSTITUTION_GROUP = "SubstitutionGroup";
   public static final String PROPERTY_SUBSTITUTION_GROUP_VALUE = "SubstitutionGroupValue";
   public static final String PROPERTY_ABSTRACT = "Abstract";
+  public static final String PROPERTY_WHITESPACE_FACET = "org.eclipse.wst.xsd.cm.properties/whitespace"; //$NON-NLS-1$
   /**
    * Definition info for element declarations.
    */
@@ -1443,27 +1444,30 @@
       }
 
       /**
-       * Returns false. This class does not support any properties.
+       * Returns true if the property is supported for this class.
        * 
        * @param propertyName -
        *          name of a property
-       * @return false.
+       * @return true if the property is supported.
        */
       public boolean supports(String propertyName)
       {
-        return false;
+    	  return (PROPERTY_WHITESPACE_FACET.equals(propertyName));
       }
 
       /**
-       * Returns null. This class does not support any properties.
+       * Returns the property value for the property name. Returns null if the
+       * property is not supported.
        * 
        * @param propertyName -
        *          name of a property
-       * @return null.
+       * @return the property value for the property name.
        */
       public Object getProperty(String propertyName)
       {
-        return null;
+    	  if(PROPERTY_WHITESPACE_FACET.equals(propertyName))
+		  	return getWhiteSpaceFacetValue();
+    	  return null;
       }
 
       /**
@@ -1475,7 +1479,7 @@
       {
         XSDSimpleTypeDefinition sc = xsdAttributeUse.getAttributeDeclaration().getTypeDefinition();
         String typeName = sc.getName();
-        return typeName != null ? typeName : "string";
+        return typeName != null ? typeName : "string";  //$NON-NLS-1$
       }
 
       /**
@@ -1544,6 +1548,18 @@
         XSDAttributeDeclaration attr = xsdAttributeUse.getAttributeDeclaration();
         return attr.getResolvedAttributeDeclaration().getTypeDefinition();
       }
+      
+      /**
+       * Obtains the whitespace facet of the XSD simple type.
+       * 
+       * @return The whitespace facet for the XSD type. If none is
+       * defined, or it is a complex type, null.
+       */
+      private String getWhiteSpaceFacetValue()
+      {
+        XSDSimpleTypeDefinition def = getXSDType().getSimpleType();
+        return (def != null && def.getEffectiveWhiteSpaceFacet() != null) ? def.getEffectiveWhiteSpaceFacet().getLexicalValue() : null ;
+      }
     }
   }
   /**
@@ -2051,26 +2067,29 @@
       }
 
       /**
-       * Returns false. This class does not support any properties.
+       * Returns true if the property is supported for this class.
        * 
        * @param propertyName -
        *          name of a property
-       * @return false.
+       * @return true if the property is supported.
        */
       public boolean supports(String propertyName)
       {
-        return false;
+        return (PROPERTY_WHITESPACE_FACET.equals(propertyName));
       }
 
       /**
-       * Returns null. This class does not support any properties.
+       * Returns the property value for the property name. Returns null if the
+       * property is not supported.
        * 
        * @param propertyName -
        *          name of a property
-       * @return null.
+       * @return the property value for the property name.
        */
       public Object getProperty(String propertyName)
       {
+        if(PROPERTY_WHITESPACE_FACET.equals(propertyName))
+        	return getWhiteSpaceFacetValue();
         return null;
       }
 
@@ -2085,7 +2104,7 @@
         XSDSimpleTypeDefinition std = getXSDType().getSimpleType();
         if (std != null)
           typeName = std.getName();
-        return typeName != null ? typeName : "string";
+        return typeName != null ? typeName : "string"; //$NON-NLS-1$
       }
 
       /**
@@ -2147,6 +2166,18 @@
       {
         return (CMDocument) getAdapter(getXSDElementDeclaration().getSchema());
       }
+      
+      /**
+       * Obtains the whitespace facet of the XSD simple type.
+       * 
+       * @return The whitespace facet for the XSD type. If none is
+       * defined, or it is a complex type, null.
+       */
+      private String getWhiteSpaceFacetValue()
+      {
+        XSDSimpleTypeDefinition def = getXSDType().getSimpleType();
+        return (def != null && def.getEffectiveWhiteSpaceFacet() != null) ? def.getEffectiveWhiteSpaceFacet().getLexicalValue() : null ;
+      }
     }
   }
   /**