[275733] Markup Validation for JSPs is strict on HTML attributes
diff --git a/bundles/org.eclipse.jst.jsp.ui/plugin.xml b/bundles/org.eclipse.jst.jsp.ui/plugin.xml
index 17b97dd..32449c6 100644
--- a/bundles/org.eclipse.jst.jsp.ui/plugin.xml
+++ b/bundles/org.eclipse.jst.jsp.ui/plugin.xml
@@ -150,7 +150,7 @@
 	<extension point="org.eclipse.wst.sse.ui.sourcevalidation">
 		<validator
 			scope="total"
-			class="org.eclipse.wst.xml.ui.internal.validation.MarkupValidator"
+			class="org.eclipse.jst.jsp.ui.internal.validation.JSPMarkupValidator"
 			id="org.eclipse.jst.jsp.ui.internal.validation.markupvalidator">
 			<contentTypeIdentifier
 				id="org.eclipse.jst.jsp.core.jspsource">
diff --git a/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/validation/JSPMarkupValidator.java b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/validation/JSPMarkupValidator.java
new file mode 100644
index 0000000..84acd78
--- /dev/null
+++ b/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/validation/JSPMarkupValidator.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     
+ *******************************************************************************/
+package org.eclipse.jst.jsp.ui.internal.validation;
+
+import org.eclipse.jst.jsp.core.internal.regions.DOMJSPRegionContexts;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionContainer;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
+import org.eclipse.wst.sse.ui.internal.reconcile.AbstractStructuredTextReconcilingStrategy;
+import org.eclipse.wst.validation.internal.provisional.core.IReporter;
+import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;
+import org.eclipse.wst.xml.ui.internal.XMLUIMessages;
+import org.eclipse.wst.xml.ui.internal.correction.ProblemIDsXML;
+import org.eclipse.wst.xml.ui.internal.validation.MarkupValidator;
+
+public class JSPMarkupValidator extends MarkupValidator {
+
+	private boolean hasXMLAttributes(IStructuredDocumentRegion structuredDocumentRegion) {
+		ITextRegionList regions = structuredDocumentRegion.getRegions();
+
+		if (regions.size() > 1 && regions.get(0).getType() == DOMRegionContext.XML_TAG_OPEN) {
+			ITextRegion region = regions.get(1);
+			if (region.getType() == DOMRegionContext.XML_TAG_NAME || region.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_NAME) {
+				// Tag name has a prefix, be strict about requiring quotes
+				if (structuredDocumentRegion.getText(region).indexOf(":") != -1) //$NON-NLS-1$
+						return true;
+			}
+		}
+		return false;
+	}
+
+	protected void checkForAttributeValue(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) {
+
+		if (structuredDocumentRegion.isDeleted()) {
+			return;
+		}
+
+		if (hasXMLAttributes(structuredDocumentRegion))
+			super.checkForAttributeValue(structuredDocumentRegion, reporter);
+
+		// check for attributes without a value
+		// track the attribute/equals/value sequence using a state of 0, 1 ,2
+		// representing the name, =, and value, respectively
+		int attrState = 0;
+		ITextRegionList textRegions = structuredDocumentRegion.getRegions();
+
+		int errorCount = 0;
+		for (int i = 0; (i < textRegions.size()) && (errorCount < AbstractStructuredTextReconcilingStrategy.ELEMENT_ERROR_LIMIT); i++) {
+			ITextRegion textRegion = textRegions.get(i);
+			if ((textRegion.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) || isTagCloseTextRegion(textRegion)) {
+				// dangling name and '='
+				if ((attrState == 2) && (i >= 2)) {
+					// create annotation
+					ITextRegion nameRegion = textRegions.get(i - 2);
+					if (!(nameRegion instanceof ITextRegionContainer)) {
+						Object[] args = {structuredDocumentRegion.getText(nameRegion)};
+						String messageText = NLS.bind(XMLUIMessages.Attribute__is_missing_a_value, args);
+
+						int start = structuredDocumentRegion.getStartOffset(nameRegion);
+						int end = structuredDocumentRegion.getEndOffset();
+						int textLength = structuredDocumentRegion.getText(nameRegion).trim().length();
+
+						// quick fix info
+						ITextRegion equalsRegion = textRegions.get(i - 2 + 1);
+						int insertOffset = structuredDocumentRegion.getTextEndOffset(equalsRegion) - end;
+						Object[] additionalFixInfo = {structuredDocumentRegion.getText(nameRegion), new Integer(insertOffset)};
+
+						addAttributeError(messageText, additionalFixInfo, start, textLength, ProblemIDsXML.MissingAttrValue, structuredDocumentRegion, reporter);
+						// annotation.setAdditionalFixInfo(additionalFixInfo);
+						// results.add(annotation);
+						errorCount++;
+					}
+				}
+				attrState = 1;
+			}
+			else if (textRegion.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_EQUALS) {
+				attrState = 2;
+			}
+			else if (textRegion.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
+				attrState = 0;
+			}
+		}
+
+	}
+
+	protected void checkQuotesForAttributeValues(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) {
+		ITextRegionList regions = structuredDocumentRegion.getRegions();
+		ITextRegion r = null;
+		String attrValueText = ""; //$NON-NLS-1$
+		int errorCount = 0;
+
+		if (hasXMLAttributes(structuredDocumentRegion))
+			super.checkQuotesForAttributeValues(structuredDocumentRegion, reporter);
+
+		for (int i = 0; (i < regions.size()) && (errorCount < AbstractStructuredTextReconcilingStrategy.ELEMENT_ERROR_LIMIT); i++) {
+			r = regions.get(i);
+			if (r.getType() != DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
+				continue;
+			}
+
+			attrValueText = structuredDocumentRegion.getText(r);
+			// attribute value includes quotes in the string
+			// split up attribute value on quotes
+			/*
+			 * WORKAROUND till
+			 * http://dev.icu-project.org/cgi-bin/icu-bugs/incoming?findid=5207
+			 * is fixed. (Also see BUG143628)
+			 */
+
+			java.util.StringTokenizer st = new java.util.StringTokenizer(attrValueText, "\"'", true); //$NON-NLS-1$
+			int size = st.countTokens();
+			// get the pieces of the attribute value
+			String one = "", two = ""; //$NON-NLS-1$ //$NON-NLS-2$
+			if (size > 0) {
+				one = st.nextToken();
+			}
+			if (size > 1) {
+				two = st.nextToken();
+			}
+			if (size > 2) {
+				// should be handled by parsing...
+				// as in we can't have an attribute value like: <element
+				// attr="a"b"c"/>
+				// and <element attr='a"b"c' /> is legal
+				continue;
+			}
+
+
+			if (size == 1) {
+				if (one.equals(DQUOTE) || one.equals(SQUOTE)) {
+					// missing closing quote
+					String message = XMLUIMessages.ReconcileStepForMarkup_0;
+					addAttributeError(message, attrValueText, structuredDocumentRegion.getStartOffset(r), attrValueText.trim().length(), ProblemIDsXML.Unclassified, structuredDocumentRegion, reporter);
+					errorCount++;
+				}
+			}
+			else if (size == 2) {
+				if ((one.equals(SQUOTE) && !two.equals(SQUOTE)) || (one.equals(DQUOTE) && !two.equals(DQUOTE))) {
+					// missing closing quote
+					String message = XMLUIMessages.ReconcileStepForMarkup_0;
+					addAttributeError(message, attrValueText, structuredDocumentRegion.getStartOffset(r), attrValueText.trim().length(), ProblemIDsXML.Unclassified, structuredDocumentRegion, reporter);
+					errorCount++;
+				}
+			}
+		}
+		// end of region for loop
+	}
+
+	private boolean isTagCloseTextRegion(ITextRegion textRegion) {
+		return (textRegion.getType() == DOMRegionContext.XML_TAG_CLOSE) || (textRegion.getType() == DOMRegionContext.XML_EMPTY_TAG_CLOSE);
+	}
+}
diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/validation/MarkupValidator.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/validation/MarkupValidator.java
index 9979f54..d0ee221 100644
--- a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/validation/MarkupValidator.java
+++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/validation/MarkupValidator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2001, 2008 IBM Corporation and others.
+ * Copyright (c) 2001, 2009 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -51,7 +51,7 @@
  * @author pavery
  */
 public class MarkupValidator implements IValidator, ISourceValidator {
-	private String DQUOTE = "\""; //$NON-NLS-1$
+	protected final static String DQUOTE = "\""; //$NON-NLS-1$
 
 	protected String SEVERITY_ATTR_MISSING_VALUE = TemporaryAnnotation.ANNOT_ERROR;
 	protected String SEVERITY_ATTR_NO_VALUE = TemporaryAnnotation.ANNOT_ERROR;
@@ -61,12 +61,12 @@
 	protected String SEVERITY_STRUCTURE = TemporaryAnnotation.ANNOT_ERROR;
 	protected String SEVERITY_SYNTAX_ERROR = TemporaryAnnotation.ANNOT_ERROR;
 	// used for attribute quote checking
-	private String SQUOTE = "'"; //$NON-NLS-1$
+	protected final static String SQUOTE = "'"; //$NON-NLS-1$
 	private final String QUICKASSISTPROCESSOR = IQuickAssistProcessor.class.getName();
 
 	private IDocument fDocument;
 
-	private void addAttributeError(String messageText, String attributeValueText, int start, int length, int problemId, IStructuredDocumentRegion sdRegion, IReporter reporter) {
+	protected final void addAttributeError(String messageText, String attributeValueText, int start, int length, int problemId, IStructuredDocumentRegion sdRegion, IReporter reporter) {
 
 		if (sdRegion.isDeleted()) {
 			return;
@@ -87,6 +87,27 @@
 		((IncrementalReporter) reporter).addAnnotationInfo(this, info);
 	}
 
+	protected final void addAttributeError(String messageText, Object[] additionalInfo, int start, int length, int problemId, IStructuredDocumentRegion sdRegion, IReporter reporter) {
+
+		if (sdRegion.isDeleted()) {
+			return;
+		}
+
+		int lineNo = getLineNumber(start);
+		LocalizedMessage message = new LocalizedMessage(IMessage.HIGH_SEVERITY, messageText);
+		message.setOffset(start);
+		message.setLength(length);
+		message.setLineNo(lineNo);
+
+		MarkupQuickAssistProcessor processor = new MarkupQuickAssistProcessor();
+		processor.setProblemId(problemId);
+		processor.setAdditionalFixInfo(additionalInfo);
+		message.setAttribute(QUICKASSISTPROCESSOR, processor);
+
+		AnnotationInfo info = new AnnotationInfo(message);
+		((IncrementalReporter) reporter).addAnnotationInfo(this, info);
+	}
+
 	private void checkAttributesInEndTag(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) {
 
 		if (structuredDocumentRegion.isDeleted()) {
@@ -205,7 +226,7 @@
 		return lineNo;
 	}
 
-	private void checkForAttributeValue(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) {
+	protected void checkForAttributeValue(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) {
 
 		if (structuredDocumentRegion.isDeleted()) {
 			return;
@@ -233,28 +254,14 @@
 
 						int start = structuredDocumentRegion.getStartOffset(nameRegion);
 						int end = structuredDocumentRegion.getEndOffset();
-						int lineNo = getLineNumber(start);
 						int textLength = structuredDocumentRegion.getText(nameRegion).trim().length();
 
-						LocalizedMessage message = new LocalizedMessage(IMessage.HIGH_SEVERITY, messageText);
-						message.setOffset(start);
-						message.setLength(textLength);
-						message.setLineNo(lineNo);
-
 						// quick fix info
 						ITextRegion equalsRegion = textRegions.get(i - 2 + 1);
 						int insertOffset = structuredDocumentRegion.getTextEndOffset(equalsRegion) - end;
 						Object[] additionalFixInfo = {structuredDocumentRegion.getText(nameRegion), new Integer(insertOffset)};
 
-						MarkupQuickAssistProcessor processor = new MarkupQuickAssistProcessor();
-						processor.setProblemId(ProblemIDsXML.MissingAttrValue);
-						processor.setAdditionalFixInfo(additionalFixInfo);
-						message.setAttribute(QUICKASSISTPROCESSOR, processor);
-
-						AnnotationInfo info = new AnnotationInfo(message);
-
-						((IncrementalReporter) reporter).addAnnotationInfo(this, info);
-
+						addAttributeError(messageText, additionalFixInfo, start, textLength, ProblemIDsXML.MissingAttrValue, structuredDocumentRegion, reporter);
 						// annotation.setAdditionalFixInfo(additionalFixInfo);
 						// results.add(annotation);
 						errorCount++;
@@ -269,22 +276,8 @@
 						String messageText = NLS.bind(XMLUIMessages.Attribute__has_no_value, args);
 						int start = structuredDocumentRegion.getStartOffset(previousRegion);
 						int textLength = structuredDocumentRegion.getText(previousRegion).trim().length();
-						int lineNo = getLineNumber(start);
 
-						LocalizedMessage message = new LocalizedMessage(IMessage.HIGH_SEVERITY, messageText);
-						message.setOffset(start);
-						message.setLength(textLength);
-						message.setLineNo(lineNo);
-
-						MarkupQuickAssistProcessor processor = new MarkupQuickAssistProcessor();
-						processor.setProblemId(ProblemIDsXML.NoAttrValue);
-						processor.setAdditionalFixInfo(structuredDocumentRegion.getText(previousRegion));
-						message.setAttribute(QUICKASSISTPROCESSOR, processor);
-
-						AnnotationInfo info = new AnnotationInfo(message);
-
-						((IncrementalReporter) reporter).addAnnotationInfo(this, info);
-
+						addAttributeError(messageText, structuredDocumentRegion.getText(previousRegion), start, textLength, ProblemIDsXML.NoAttrValue, structuredDocumentRegion, reporter);
 						errorCount++;
 					}
 				}
@@ -372,7 +365,7 @@
 		}
 	}
 
-	private void checkQuotesForAttributeValues(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) {
+	protected void checkQuotesForAttributeValues(IStructuredDocumentRegion structuredDocumentRegion, IReporter reporter) {
 		ITextRegionList regions = structuredDocumentRegion.getRegions();
 		ITextRegion r = null;
 		String attrValueText = ""; //$NON-NLS-1$