Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate')
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/AbstractErrorInfo.java40
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/CMUtil.java200
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/CompositeValidator.java74
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/DocumentPropagatingValidator.java58
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ElementPropagatingValidator.java50
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorInfo.java26
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorInfoImpl.java56
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorState.java41
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/FMUtil.java103
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLAttributeValidator.java207
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLDocumentContentValidator.java194
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLElementAncestorValidator.java70
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLElementContentValidator.java178
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLSimpleDocumentValidator.java39
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLSimpleValidator.java42
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLValidationAdapterFactory.java72
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/MessageFactory.java256
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/NamespaceValidator.java127
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/NullValidator.java34
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/PrimeValidator.java25
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/SMUtil.java36
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/Segment.java64
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/SyntaxValidator.java345
23 files changed, 2337 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/AbstractErrorInfo.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/AbstractErrorInfo.java
new file mode 100644
index 0000000000..5e6ee85f30
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/AbstractErrorInfo.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+abstract class AbstractErrorInfo implements ErrorInfo, ErrorState {
+
+
+ private int state = NONE_ERROR;
+ private Segment seg = null;
+
+ public AbstractErrorInfo(int state, Segment seg) {
+ super();
+ this.state = state;
+ this.seg = seg;
+ }
+
+ abstract public String getHint();
+
+ abstract public short getTargetType();
+
+ public int getLength() {
+ return (seg == null) ? 0 : seg.getLength();
+ }
+
+ public int getOffset() {
+ return (seg == null) ? 0 : seg.getOffset();
+ }
+
+ public int getState() {
+ return this.state;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/CMUtil.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/CMUtil.java
new file mode 100644
index 0000000000..38f351d2e1
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/CMUtil.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+import java.util.Iterator;
+
+import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.common.contentmodel.CMContent;
+import org.eclipse.wst.common.contentmodel.CMDataType;
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.common.contentmodel.CMGroup;
+import org.eclipse.wst.common.contentmodel.CMNode;
+import org.eclipse.wst.common.contentmodel.CMNodeList;
+import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery;
+import org.eclipse.wst.html.core.HTMLCMProperties;
+import org.eclipse.wst.html.core.modelquery.HMQUtil;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+final class CMUtil {
+
+ /**
+ * Never instantiate!
+ */
+ private CMUtil() {
+ super();
+ }
+
+ /**
+ * You cannot always retrieve HTMLElementDeclaration via an Element instance.
+ * Because, it occasionally a JSP custom tag. -- 9/7/2001
+ */
+ public static CMElementDeclaration getDeclaration(Element target) {
+ Document doc = target.getOwnerDocument();
+ ModelQuery query = ModelQueryUtil.getModelQuery(doc);
+ return query.getCMElementDeclaration(target);
+ }
+
+ /**
+ */
+ public static boolean isCaseSensitive(CMElementDeclaration decl) {
+ if (decl == null || (!decl.supports(HTMLCMProperties.SHOULD_IGNORE_CASE)))
+ return false;
+ return !((Boolean) decl.getProperty(HTMLCMProperties.SHOULD_IGNORE_CASE)).booleanValue();
+ }
+
+ /**
+ */
+ private static boolean isChild(CMContent content, CMElementDeclaration target) {
+ switch (content.getNodeType()) {
+ case CMNode.ELEMENT_DECLARATION :
+ if (isWholeTagOmissible((CMElementDeclaration) content))
+ if (isChild(((CMElementDeclaration) content).getContent(), target))
+ return true;
+ return isSameDeclaration((CMElementDeclaration) content, target);
+ case CMNode.GROUP :
+ CMNodeList children = ((CMGroup) content).getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ CMNode child = children.item(i);
+ switch (child.getNodeType()) {
+ case CMNode.ELEMENT_DECLARATION :
+ if (isWholeTagOmissible((CMElementDeclaration) child))
+ if (isChild(((CMElementDeclaration) child).getContent(), target))
+ return true;
+ if (isSameDeclaration((CMElementDeclaration) child, target))
+ return true;
+ continue; // Go next child.
+ case CMNode.GROUP :
+ if (isChild((CMContent) child, target))
+ return true;
+ continue; // Go next child.
+ default :
+ continue; // Go next child.
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ */
+ public static boolean isEndTagOmissible(CMElementDeclaration decl) {
+ if (!(decl.supports(HTMLCMProperties.OMIT_TYPE)))
+ return false;
+ String omitType = (String) decl.getProperty(HTMLCMProperties.OMIT_TYPE);
+ return !omitType.equals(HTMLCMProperties.Values.OMIT_NONE);
+ }
+
+ /**
+ */
+ public static boolean isWholeTagOmissible(CMElementDeclaration decl) {
+ if (!(decl.supports(HTMLCMProperties.OMIT_TYPE)))
+ return false;
+ String omitType = (String) decl.getProperty(HTMLCMProperties.OMIT_TYPE);
+ return omitType.equals(HTMLCMProperties.Values.OMIT_BOTH);
+ }
+
+ /**
+ */
+ public static boolean isJSP(CMElementDeclaration decl) {
+ if (!decl.supports(HTMLCMProperties.IS_JSP))
+ return false;
+ return ((Boolean) decl.getProperty(HTMLCMProperties.IS_JSP)).booleanValue();
+ }
+
+ /**
+ */
+ public static boolean isXHTML(CMElementDeclaration decl) {
+ if (!decl.supports(HTMLCMProperties.IS_XHTML))
+ return false;
+ return ((Boolean) decl.getProperty(HTMLCMProperties.IS_XHTML)).booleanValue();
+ }
+
+ /**
+ * The method to distinguish HTML and XHTML from other mark up.
+ * This method returns true if the target is,
+ * (1) not JSP,
+ * (2) not SSI.
+ */
+ public static boolean isHTML(CMElementDeclaration decl) {
+ return (!isJSP(decl)) && (!isSSI(decl));
+ }
+
+ /**
+ */
+ private static boolean isSameDeclaration(CMElementDeclaration aDec, CMElementDeclaration otherDec) {
+ return aDec.getElementName() == otherDec.getElementName();
+ }
+
+ /**
+ */
+ public static boolean isSSI(CMElementDeclaration edec) {
+ if (edec == null)
+ return false;
+ if (!edec.supports(HTMLCMProperties.IS_SSI))
+ return false;
+ return ((Boolean) edec.getProperty(HTMLCMProperties.IS_SSI)).booleanValue();
+ }
+
+ /**
+ * Call this method only when the parent content type is one of
+ * the following: ANY, ELEMENT, or MIXED.
+ */
+ public static boolean isValidChild(CMElementDeclaration parent, CMElementDeclaration child) {
+ if (parent == null || child == null)
+ return false;
+ if (isHTML(parent) && (!isHTML(child)))
+ return true;
+ CMContent content = parent.getContent();
+ if (content == null)
+ return false;
+ return isChild(content, child);
+ }
+
+ public static boolean isForeign(Element target) {
+ if (!(target instanceof XMLElement))
+ return true;
+ XMLElement element = (XMLElement) target;
+ return !element.isGlobalTag();
+ }
+
+ /**
+ * This method returns true if all of the following conditions are met:
+ * (1) value type is ENUM,
+ * (2) only one value is defined in the enumeration,
+ * (3) the value has same name to the attribute name.
+ */
+ public static boolean isBooleanAttr(CMAttributeDeclaration adec) {
+ CMDataType attrtype = adec.getAttrType();
+ if (attrtype == null)
+ return false;
+ if (attrtype.getDataTypeName() != CMDataType.ENUM)
+ return false;
+ String[] values = attrtype.getEnumeratedValues();
+ if (values.length != 1)
+ return false;
+ return values[0].equals(adec.getAttrName());
+ }
+
+ public static boolean isValidInclusion(CMElementDeclaration decl, Element parent) {
+ Iterator iter = HMQUtil.getInclusions(parent).iterator();
+ while (iter.hasNext()) {
+ CMElementDeclaration inclusion = (CMElementDeclaration) iter.next();
+ if (isSameDeclaration(decl, inclusion))
+ return true;
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/CompositeValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/CompositeValidator.java
new file mode 100644
index 0000000000..1c5a6017e5
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/CompositeValidator.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.sse.core.validate.ValidationAdapter;
+import org.eclipse.wst.sse.core.validate.ValidationReporter;
+import org.eclipse.wst.xml.core.internal.validate.ValidationComponent;
+
+abstract class CompositeValidator extends ValidationComponent {
+
+ protected Vector components = new Vector();
+
+ /**
+ * CompositeValidator constructor comment.
+ */
+ public CompositeValidator() {
+ super();
+ }
+
+ /**
+ */
+ public void setReporter(ValidationReporter reporter) {
+ super.setReporter(reporter);
+
+ Iterator i = components.iterator();
+ while (i.hasNext()) {
+ ValidationAdapter component = (ValidationAdapter) i.next();
+ if (component == null)
+ continue;
+ component.setReporter(reporter);
+ }
+ }
+
+ /**
+ */
+ public void validate(IndexedRegion node) {
+ Iterator i = components.iterator();
+ while (i.hasNext()) {
+ ValidationComponent component = (ValidationComponent) i.next();
+ if (component == null)
+ continue;
+ component.validate(node);
+ }
+ }
+
+ /**
+ */
+ void add(ValidationComponent validator) {
+ components.add(validator);
+ }
+
+ /**
+ * This method registers all components in 'validators'.
+ * Each derivative must call this methid in its constructor.
+ */
+ protected void register(ValidationComponent[] validators) {
+ for (int i = 0; i < validators.length; i++) {
+ if (validators[i] != null)
+ add(validators[i]);
+ }
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/DocumentPropagatingValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/DocumentPropagatingValidator.java
new file mode 100644
index 0000000000..51edfcda31
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/DocumentPropagatingValidator.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.sse.core.validate.ValidationAdapter;
+import org.eclipse.wst.sse.core.validate.ValidationReporter;
+import org.eclipse.wst.xml.core.internal.validate.AbstractPropagatingValidator;
+import org.eclipse.wst.xml.core.internal.validate.ValidationComponent;
+
+class DocumentPropagatingValidator extends AbstractPropagatingValidator {
+
+
+ private ValidationComponent validator = new HTMLSimpleDocumentValidator();
+ private ElementPropagatingValidator propagatee = new ElementPropagatingValidator();
+
+ public DocumentPropagatingValidator() {
+ super();
+ }
+
+ public void validate(IndexedRegion node) {
+ getPropagatee().setReporter(this.reporter);
+ super.validate(node);
+ }
+
+ public boolean isAdapterForType(Object type) {
+ return (type == DocumentPropagatingValidator.class || super.isAdapterForType(type));
+ }
+
+ public void setReporter(ValidationReporter reporter) {
+ super.setReporter(reporter);
+ validator.setReporter(reporter);
+ propagatee.setReporter(reporter);
+ }
+
+ /**
+ * @see com.ibm.sed.validate.html.AbstractPropagatingValidator#getPropagatee()
+ */
+ protected final ValidationComponent getPropagatee() {
+ return propagatee;
+ }
+
+ /**
+ * @see com.ibm.sed.validate.html.AbstractPropagatingValidator#getValidator()
+ */
+ protected final ValidationAdapter getValidator() {
+ return validator;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ElementPropagatingValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ElementPropagatingValidator.java
new file mode 100644
index 0000000000..bd10b279a2
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ElementPropagatingValidator.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+import org.eclipse.wst.sse.core.validate.ValidationAdapter;
+import org.eclipse.wst.sse.core.validate.ValidationReporter;
+import org.eclipse.wst.xml.core.internal.validate.AbstractPropagatingValidator;
+import org.eclipse.wst.xml.core.internal.validate.ValidationComponent;
+
+class ElementPropagatingValidator extends AbstractPropagatingValidator {
+
+
+ private ValidationComponent validator = new HTMLSimpleValidator();
+
+ public ElementPropagatingValidator() {
+ super();
+ }
+
+ public boolean isAdapterForType(Object type) {
+ return (type == ElementPropagatingValidator.class || super.isAdapterForType(type));
+ }
+
+ public void setReporter(ValidationReporter reporter) {
+ super.setReporter(reporter);
+ validator.setReporter(reporter);
+ }
+
+ /**
+ * @see com.ibm.sed.validate.html.AbstractPropagatingValidator#getPropagatee()
+ */
+ protected ValidationComponent getPropagatee() {
+ return this;
+ }
+
+ /**
+ * @see com.ibm.sed.validate.html.AbstractPropagatingValidator#getValidator()
+ */
+ protected ValidationAdapter getValidator() {
+ return validator;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorInfo.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorInfo.java
new file mode 100644
index 0000000000..01ce2c0799
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorInfo.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+interface ErrorInfo {
+
+ public String getHint();
+
+ public int getLength();
+
+ public int getOffset();
+
+ public int getState();
+
+ public short getTargetType();
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorInfoImpl.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorInfoImpl.java
new file mode 100644
index 0000000000..f10294e99f
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorInfoImpl.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+final class ErrorInfoImpl extends AbstractErrorInfo {
+
+ private Node target = null;
+
+ // private Segment seg = null;
+ /**
+ */
+ public ErrorInfoImpl(int state, Segment errorSeg, Node target) {
+ super(state, errorSeg);
+ this.target = target;
+ }
+
+ /**
+ */
+ public String getHint() {
+ switch (target.getNodeType()) {
+ case Node.ATTRIBUTE_NODE :
+ switch (getState()) {
+ case UNDEFINED_VALUE_ERROR :
+ case MISMATCHED_VALUE_ERROR :
+ case UNCLOSED_ATTR_VALUE :
+ //D210422
+ return ((Attr) target).getValue();
+ default :
+ return target.getNodeName();
+ }
+ case Node.TEXT_NODE :
+ return ((Text) target).getData();
+ case Node.ELEMENT_NODE :
+ default :
+ return target.getNodeName();
+ }
+ }
+
+ public short getTargetType() {
+ return target.getNodeType();
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorState.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorState.java
new file mode 100644
index 0000000000..2c0eb26eba
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/ErrorState.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+interface ErrorState {
+ static final int NONE_ERROR = 0;
+ // generic error
+ static final int UNDEFINED_NAME_ERROR = 11;
+ static final int UNDEFINED_VALUE_ERROR = 12;
+ static final int MISMATCHED_VALUE_ERROR = 13;
+ // format error
+ static final int FORMAT_ERROR_LEVEL = 100;
+ static final int INVALID_NAME_ERROR = 101;
+ static final int INVALID_CHAR_ERROR = 102;
+ static final int MISMATCHED_ERROR = 103;
+ static final int MISMATCHED_END_TAG_ERROR = 104;
+ static final int MISSING_START_TAG_ERROR = 105;
+ static final int MISSING_END_TAG_ERROR = 106;
+ static final int UNNECESSARY_END_TAG_ERROR = 107;
+ static final int INVALID_ATTR_ERROR = 108;
+ static final int INVALID_DIRECTIVE_ERROR = 109;
+ static final int UNCLOSED_TAG_ERROR = 110;
+ static final int UNCLOSED_END_TAG_ERROR = 111;
+ static final int INVALID_EMPTY_ELEMENT_TAG = 112;
+ static final int UNCLOSED_ATTR_VALUE = 113; //D210422
+ // layout error
+ static final int LAYOUT_ERROR_LEVEL = 1000;
+ static final int INVALID_CONTENT_ERROR = 1001;
+ static final int DUPLICATE_ERROR = 1002;
+ static final int COEXISTENCE_ERROR = 1003;
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/FMUtil.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/FMUtil.java
new file mode 100644
index 0000000000..da4f240415
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/FMUtil.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+import java.util.Iterator;
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionContainer;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+final class FMUtil {
+
+ public final static int SEG_NONE = 0;
+ public final static int SEG_WHOLE_TAG = 1;
+ public final static int SEG_START_TAG = 2;
+ public final static int SEG_END_TAG = 3;
+
+ /**
+ */
+ private FMUtil() {
+ super();
+ }
+
+ /**
+ */
+ public final static Segment getSegment(XMLNode target, int segType) {
+ if (target == null)
+ return new Segment(0, 0);
+ Segment seg = null;
+ IStructuredDocumentRegion startTag = null;
+ IStructuredDocumentRegion endTag = null;
+ switch (segType) {
+ case SEG_WHOLE_TAG :
+ startTag = target.getFirstStructuredDocumentRegion();
+ if (startTag != null) {
+ endTag = target.getLastStructuredDocumentRegion();
+ seg = new Segment(startTag, endTag);
+ }
+ else {
+ int startOffset = target.getStartOffset();
+ int endOffset = target.getEndOffset();
+ seg = new Segment(startOffset, endOffset - startOffset);
+ }
+ break;
+ case SEG_START_TAG :
+ startTag = target.getStartStructuredDocumentRegion();
+ if (startTag != null) {
+ seg = new Segment(startTag);
+ }
+ else {
+ seg = new Segment(target.getStartOffset(), 0);
+ }
+ break;
+ case SEG_END_TAG :
+ endTag = target.getEndStructuredDocumentRegion();
+ if (endTag != null) {
+ seg = new Segment(endTag);
+ }
+ else {
+ seg = new Segment(target.getEndOffset(), 0);
+ }
+ break;
+ case SEG_NONE :
+ default :
+ return new Segment(0, 0);
+ }
+ return seg;
+ }
+
+ /**
+ */
+ public final static boolean hasJSPRegion(ITextRegion container) {
+ if (!(container instanceof ITextRegionContainer))
+ return false;
+ ITextRegionList regions = ((ITextRegionContainer) container).getRegions();
+ if (regions == null)
+ return false;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ if (region == null)
+ continue;
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_OPEN || regionType == XMLJSPRegionContexts.JSP_SCRIPTLET_OPEN || regionType == XMLJSPRegionContexts.JSP_EXPRESSION_OPEN || regionType == XMLJSPRegionContexts.JSP_DECLARATION_OPEN || regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_OPEN)
+ return true;
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLAttributeValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLAttributeValidator.java
new file mode 100644
index 0000000000..a57a30720d
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLAttributeValidator.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.common.contentmodel.CMDataType;
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.common.contentmodel.CMNamedNodeMap;
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.document.XMLAttr;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+public class HTMLAttributeValidator extends PrimeValidator {
+
+ private static final int REGION_NAME = 1;
+ private static final int REGION_VALUE = 2;
+ //<<D210422
+ private static final char SINGLE_QUOTE = '\'';
+ private static final char DOUBLE_QUOTE = '\"';
+
+ //D210422
+ /**
+ * HTMLAttributeValidator constructor comment.
+ */
+ public HTMLAttributeValidator() {
+ super();
+ }
+
+ /**
+ */
+ private Segment getErrorSegment(XMLNode errorNode, int regionType) {
+ ITextRegion rgn = null;
+ switch (regionType) {
+ case REGION_NAME :
+ rgn = errorNode.getNameRegion();
+ break;
+ case REGION_VALUE :
+ rgn = errorNode.getValueRegion();
+ break;
+ default :
+ // nothing to do.
+ break;
+ }
+ if (rgn != null) {
+ if (errorNode instanceof XMLAttr) {
+ XMLElement ownerElement = (XMLElement) ((XMLAttr) errorNode).getOwnerElement();
+ if (ownerElement != null) {
+ int regionStartOffset = ownerElement.getFirstStructuredDocumentRegion().getStartOffset(rgn);
+ int regionLength = rgn.getLength();
+ return new Segment(regionStartOffset, regionLength);
+ }
+ }
+ }
+ return new Segment(errorNode.getStartOffset(), 0);
+ }
+
+ /**
+ * Allowing the INodeAdapter to compare itself against the type
+ * allows it to return true in more than one case.
+ */
+ public boolean isAdapterForType(Object type) {
+ return ((type == HTMLAttributeValidator.class) || super.isAdapterForType(type));
+ }
+
+ /**
+ */
+ public void validate(IndexedRegion node) {
+ Element target = (Element) node;
+ if (CMUtil.isForeign(target))
+ return;
+ CMElementDeclaration edec = CMUtil.getDeclaration(target);
+ if (edec == null)
+ return;
+ CMNamedNodeMap declarations = edec.getAttributes();
+
+ NamedNodeMap attrs = target.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ int rgnType = REGION_NAME;
+ int state = ErrorState.NONE_ERROR;
+ Attr a = (Attr) attrs.item(i);
+ // D203637; If the target attr has prefix, the validator should not
+ // warn about it. That is, just ignore. It is able to check whether
+ // an attr has prefix or not by calling XMLAttr#isGlobalAttr().
+ // When a attr has prefix (not global), it returns false.
+ boolean isXMLAttr = a instanceof XMLAttr;
+ if (isXMLAttr) {
+ XMLAttr xmlattr = (XMLAttr) a;
+ if (!xmlattr.isGlobalAttr())
+ continue; // skip futher validation and begin next loop.
+ }
+
+ CMAttributeDeclaration adec = (CMAttributeDeclaration) declarations.getNamedItem(a.getName());
+ if (adec == null) {
+ // No attr declaration was found. That is, the attr name is undefined.
+ // but not regard it as undefined name if it includes JSP
+ if (!FMUtil.hasJSPRegion(((XMLNode) a).getNameRegion())) {
+ rgnType = REGION_NAME;
+ state = ErrorState.UNDEFINED_NAME_ERROR;
+ }
+ }
+ else {
+ // The attr declaration was found.
+ // At 1st, the name should be checked.
+ if (CMUtil.isHTML(edec) && (!CMUtil.isXHTML(edec))) {
+ // If the target element is pure HTML (not XHTML), some attributes
+ // might be written in boolean format. It should be check specifically.
+ if (CMUtil.isBooleanAttr(adec) && ((XMLAttr) a).hasNameOnly())
+ continue; // OK, keep going. No more check is needed against this attr.
+ }
+ else {
+ // If the target is other than pure HTML (JSP or XHTML), the name
+ // must be checked exactly (ie in case sensitive way).
+ String actual = a.getName();
+ String desired = adec.getAttrName();
+ if (!actual.equals(desired)) { // case mismatch
+ rgnType = REGION_NAME;
+ state = ErrorState.MISMATCHED_ERROR;
+ }
+ }
+ // Then, the value must be checked.
+ if (state == ErrorState.NONE_ERROR) { // Need more check.
+ // Now, the value should be checked, if the type is ENUM.
+ CMDataType attrType = adec.getAttrType();
+ String actualValue = a.getValue();
+ if (attrType.getImpliedValueKind() == CMDataType.IMPLIED_VALUE_FIXED) {
+ // Check FIXED value.
+ String validValue = attrType.getImpliedValue();
+ if (!actualValue.equals(validValue)) {
+ rgnType = REGION_VALUE;
+ state = ErrorState.UNDEFINED_VALUE_ERROR;
+ }
+ }
+ else {
+ String[] candidates = attrType.getEnumeratedValues();
+ if (candidates != null && candidates.length > 0) {
+ // several candidates are found.
+ boolean found = false;
+ for (int index = 0; index < candidates.length; index++) {
+ String candidate = candidates[index];
+ // At 1st, compare ignoring case.
+ if (actualValue.equalsIgnoreCase(candidate)) {
+ found = true;
+ if (CMUtil.isCaseSensitive(edec) && (!actualValue.equals(candidate))) {
+ rgnType = REGION_VALUE;
+ state = ErrorState.MISMATCHED_VALUE_ERROR;
+ }
+ break; // exit the loop.
+ }
+ }
+ if (!found) {
+ // No candidate was found. That is, actualValue is invalid.
+ // but not regard it as undefined value if it includes JSP.
+ if (!FMUtil.hasJSPRegion(((XMLNode) a).getValueRegion())) {
+ rgnType = REGION_VALUE;
+ state = ErrorState.UNDEFINED_VALUE_ERROR;
+ }
+ }
+ }
+ }
+ }
+ //<<D210422
+ if (state == ErrorState.NONE_ERROR) { // Need more check.
+ if (isXMLAttr) {
+ String source = ((XMLAttr) a).getValueRegionText();
+ if (source != null) {
+ char firstChar = source.charAt(0);
+ char lastChar = source.charAt(source.length() - 1);
+ if (isQuote(firstChar) || isQuote(lastChar)) {
+ if (lastChar != firstChar) {
+ rgnType = REGION_VALUE;
+ state = ErrorState.UNCLOSED_ATTR_VALUE;
+ }
+ }
+ }
+ }
+ }
+ //D210422
+ }
+ if (state != ErrorState.NONE_ERROR) {
+ Segment seg = getErrorSegment((XMLNode) a, rgnType);
+ if (seg != null)
+ reporter.report(MessageFactory.createMessage(new ErrorInfoImpl(state, seg, a)));
+ }
+ }
+ }
+
+ //<<D214022
+ private boolean isQuote(char c) {
+ return (c == SINGLE_QUOTE) || (c == DOUBLE_QUOTE);
+ }
+ //D210422
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLDocumentContentValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLDocumentContentValidator.java
new file mode 100644
index 0000000000..14e298aed7
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLDocumentContentValidator.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.html.core.HTML40Namespace;
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.xml.core.document.DocumentTypeAdapter;
+import org.eclipse.wst.xml.core.document.XMLDocument;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.eclipse.wst.xml.core.document.XMLText;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class HTMLDocumentContentValidator extends PrimeValidator {
+
+
+ private final static class Division {
+ private Vector explicitHtmls = new Vector();
+ private Vector rest = new Vector();
+
+ public Division(Document document, NodeList children) {
+ String rootTagName = getRootTagName(document);
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (isHtmlTag(child, rootTagName)) {
+ explicitHtmls.add(child);
+ }
+ else {
+ rest.add(child);
+ }
+ }
+ }
+
+ public boolean hasExplicitHtmls() {
+ return explicitHtmls.size() > 0;
+ }
+
+ public List getExplicitHtmls() {
+ return explicitHtmls;
+ }
+
+ public Iterator getRestNodes() {
+ return rest.iterator();
+ }
+
+ /* utilities */
+ private static boolean isHtmlTag(Node node, String tagName) {
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ return false;
+ return ((Element) node).getTagName().equalsIgnoreCase(tagName);
+ }
+
+ private static String getRootTagName(Document document) {
+ DocumentTypeAdapter adapter = (DocumentTypeAdapter) ((XMLDocument) document).getAdapterFor(DocumentTypeAdapter.class);
+ if (adapter != null) {
+ DocumentType docType = adapter.getDocumentType();
+ if (docType != null) {
+ return docType.getName();
+ }
+ }
+
+ return HTML40Namespace.ElementName.HTML;
+ }
+ }
+
+ /**
+ * HTMLDocumentContentValidator constructor comment.
+ */
+ public HTMLDocumentContentValidator() {
+ super();
+ }
+
+ /**
+ * Allowing the INodeAdapter to compare itself against the type
+ * allows it to return true in more than one case.
+ */
+ public boolean isAdapterForType(Object type) {
+ return ((type == HTMLDocumentContentValidator.class) || super.isAdapterForType(type));
+ }
+
+ /**
+ */
+ public void validate(IndexedRegion node) {
+ // isFragment check should be more intelligent.
+ boolean isFragment = true;
+
+ Document target = (Document) node;
+ NodeList children = target.getChildNodes();
+ if (children == null)
+ return;
+
+ Division division = new Division(target, children);
+ if (division.hasExplicitHtmls()) {
+ isFragment = false;
+
+ List explicits = division.getExplicitHtmls();
+ if (explicits.size() > 1) {
+ for (int i = 1; i < explicits.size(); i++) {
+ Element html = (Element) explicits.get(i);
+ // report error (duplicate)
+ Segment errorSeg = FMUtil.getSegment((XMLNode) html, FMUtil.SEG_START_TAG);
+ if (errorSeg != null)
+ reporter.report(MessageFactory.createMessage(new ErrorInfoImpl(ErrorState.DUPLICATE_ERROR, errorSeg, html)));
+ }
+ }
+ }
+ validateContent(division.getRestNodes(), isFragment);
+ }
+
+ /*
+ * This methods validate nodes other than HTML elements.
+ */
+ private void validateContent(Iterator children, boolean isFragment) {
+ boolean foundDoctype = false;
+ while (children.hasNext()) {
+ XMLNode child = (XMLNode) children.next();
+
+ int error = ErrorState.NONE_ERROR;
+ int segType = FMUtil.SEG_WHOLE_TAG;
+
+ switch (child.getNodeType()) {
+ case Node.ELEMENT_NODE :
+ if (! isFragment) {
+ Element childElem = (Element) child;
+ CMElementDeclaration ced = CMUtil.getDeclaration(childElem);
+ // Undefined element is valid.
+ if (ced == null)
+ continue;
+ // JSP (includes custom tags) and SSI are valid.
+ if (CMUtil.isForeign(childElem) || CMUtil.isSSI(ced))
+ continue; // Defect 186774
+
+ // report error (invalid content)
+ error = ErrorState.INVALID_CONTENT_ERROR;
+ // mark the whole start tag as error.
+ segType = FMUtil.SEG_START_TAG;
+ }
+ break;
+ case Node.TEXT_NODE :
+ if (! isFragment) {
+ // TEXT node is valid when it contains white space characters only.
+ // Otherwise, it is invalid content.
+ if (((XMLText) child).isWhitespace())
+ continue;
+ error = ErrorState.INVALID_CONTENT_ERROR;
+ segType = FMUtil.SEG_WHOLE_TAG;
+ }
+ break;
+ case Node.DOCUMENT_TYPE_NODE :
+ // DOCTYPE is also valid when it appears once and only once.
+ if (!foundDoctype) {
+ foundDoctype = true;
+ continue;
+ }
+ error = ErrorState.DUPLICATE_ERROR;
+ segType = FMUtil.SEG_WHOLE_TAG;
+ break;
+ case Node.COMMENT_NODE :
+ // always valid.
+ case Node.PROCESSING_INSTRUCTION_NODE :
+ continue;
+ default :
+ if (! isFragment) {
+ error = ErrorState.INVALID_CONTENT_ERROR;
+ segType = FMUtil.SEG_WHOLE_TAG;
+ }
+ break;
+ }
+ if (error != ErrorState.NONE_ERROR) {
+ Segment errorSeg = FMUtil.getSegment(child, segType);
+ if (errorSeg != null)
+ reporter.report(MessageFactory.createMessage(new ErrorInfoImpl(error, errorSeg, child)));
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLElementAncestorValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLElementAncestorValidator.java
new file mode 100644
index 0000000000..b4c26b4561
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLElementAncestorValidator.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.common.contentmodel.CMNamedNodeMap;
+import org.eclipse.wst.common.contentmodel.CMNode;
+import org.eclipse.wst.html.core.HTMLCMProperties;
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.Element;
+
+public class HTMLElementAncestorValidator extends PrimeValidator {
+
+ /**
+ * HTMLElementAncestorValidator constructor comment.
+ */
+ public HTMLElementAncestorValidator() {
+ super();
+ }
+
+ /**
+ * Allowing the INodeAdapter to compare itself against the type
+ * allows it to return true in more than one case.
+ */
+ public boolean isAdapterForType(Object type) {
+ return ((type == HTMLElementAncestorValidator.class) || super.isAdapterForType(type));
+ }
+
+ /**
+ * Check exclusion which is defined in only HTML DTD (SGML).
+ */
+ public void validate(IndexedRegion node) {
+ Element target = (Element) node;
+ if (CMUtil.isForeign(target))
+ return;
+ CMElementDeclaration dec = CMUtil.getDeclaration(target);
+ if (dec == null)
+ return; // cannot validate.
+ if (!CMUtil.isHTML(dec))
+ return; // no need to validate
+ if (!dec.supports(HTMLCMProperties.PROHIBITED_ANCESTORS))
+ return; // cannot validate.
+ CMNamedNodeMap prohibited = (CMNamedNodeMap) dec.getProperty(HTMLCMProperties.PROHIBITED_ANCESTORS);
+ if (prohibited.getLength() <= 0)
+ return; // no prohibited ancestors.
+
+ Element parent = SMUtil.getParentElement(target);
+ while (parent != null) {
+ CMNode pdec = prohibited.getNamedItem(parent.getNodeName());
+ if (pdec != null) { // prohibited element is found in ancestors.
+ Segment errorSeg = FMUtil.getSegment((XMLNode) node, FMUtil.SEG_START_TAG);
+ if (errorSeg != null)
+ reporter.report(MessageFactory.createMessage(new ErrorInfoImpl(ErrorState.INVALID_CONTENT_ERROR, errorSeg, target)));
+ break; // If one prohibited ancestor is found, it's enough.
+ }
+ parent = SMUtil.getParentElement(parent);
+ }
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLElementContentValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLElementContentValidator.java
new file mode 100644
index 0000000000..007c225719
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLElementContentValidator.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.eclipse.wst.xml.core.document.XMLText;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class HTMLElementContentValidator extends PrimeValidator {
+
+ /**
+ * HTMLElementContentValidator constructor comment.
+ */
+ public HTMLElementContentValidator() {
+ super();
+ }
+
+ /**
+ * Allowing the INodeAdapter to compare itself against the type
+ * allows it to return true in more than one case.
+ */
+ public boolean isAdapterForType(Object type) {
+ return ((type == HTMLElementContentValidator.class) || super.isAdapterForType(type));
+ }
+
+ /**
+ */
+ public void validate(IndexedRegion node) {
+ Element target = (Element) node;
+ if (CMUtil.isForeign(target))
+ return;
+
+ validateContent(target, target.getChildNodes());
+ }
+
+ private void validateContent(Element parent, NodeList children) {
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child == null)
+ continue;
+
+ // perform actual validation
+ validateNode(parent, child);
+ }
+ }
+
+// private int countExplicitSiblings(Element parent, String tagName) {
+// NodeList children = parent.getChildNodes();
+// int count = 0;
+// for (int i = 0; i < children.getLength(); i++) {
+// Node child = children.item(i);
+// if (child.getNodeType() != Node.ELEMENT_NODE)
+// continue;
+// if (tagName.equalsIgnoreCase(((Element) child).getTagName())) {
+// count++;
+// }
+// }
+// return count;
+// }
+
+ /* The implementation of the following method is practical but accurate.
+ * The accurate maximum occurence should be retreive from the content model.
+ * However, it is useful enough, since almost implicit elements are HTML,
+ * HEAD, or BODY.
+ */
+// private int getMaxOccur(Element parent, String childTag) {
+// return 1;
+// }
+
+ private void validateNode(Element target, Node child) {
+ // NOTE: If the target element is 'UNKNOWN', that is, it has no
+ // element declaration, the content type of the element should be
+ // regarded as 'ANY'. -- 9/10/2001
+ int contentType = CMElementDeclaration.ANY;
+ CMElementDeclaration edec = CMUtil.getDeclaration(target);
+ if (edec != null)
+ contentType = edec.getContentType();
+
+ int error = ErrorState.NONE_ERROR;
+ int segType = FMUtil.SEG_WHOLE_TAG;
+
+ switch (child.getNodeType()) {
+ case Node.ELEMENT_NODE :
+ Element childElem = (Element) child;
+ // Defect 200321:
+ // This validator cares only HTML/XHTML elements. If a child is
+ // an element of foreign markup languages, just ignore it.
+ if (CMUtil.isForeign(childElem))
+ return;
+
+ CMElementDeclaration ced = CMUtil.getDeclaration((Element) child);
+ // Defect 186774: If a child is not one of HTML elements,
+ // it should be regarded as a valid child regardless the
+ // type of the parent content model. -- 10/12/2001
+ if (ced == null || CMUtil.isSSI(ced) || (!CMUtil.isHTML(ced)))
+ return;
+
+ switch (contentType) {
+ case CMElementDeclaration.ANY :
+ // Keep going.
+ return;
+ case CMElementDeclaration.ELEMENT :
+ case CMElementDeclaration.MIXED :
+ if (ced == null)
+ return;
+ if (CMUtil.isValidChild(edec, ced))
+ return;
+ // Now, it is the time to check inclusion, unless the target
+ // document is not a XHTML.
+ if (!CMUtil.isXHTML(edec)) {
+ // pure HTML
+ if (CMUtil.isValidInclusion(ced, target))
+ return;
+ }
+ error = ErrorState.INVALID_CONTENT_ERROR;
+ break;
+ default :
+ error = ErrorState.INVALID_CONTENT_ERROR;
+ break;
+ }
+ // Mark the whole START tag as an error segment.
+ segType = FMUtil.SEG_START_TAG;
+ break;
+ case Node.TEXT_NODE :
+ switch (contentType) {
+ case CMElementDeclaration.ANY :
+ case CMElementDeclaration.MIXED :
+ case CMElementDeclaration.PCDATA :
+ case CMElementDeclaration.CDATA :
+ // D184339
+ // Keep going.
+ return;
+ case CMElementDeclaration.ELEMENT :
+ case CMElementDeclaration.EMPTY :
+ if (((XMLText) child).isWhitespace())
+ return;
+ error = ErrorState.INVALID_CONTENT_ERROR;
+ break;
+ default :
+ error = ErrorState.INVALID_CONTENT_ERROR;
+ break;
+ }
+ // Mark the whole node as an error segment.
+ segType = FMUtil.SEG_WHOLE_TAG;
+ break;
+ case Node.COMMENT_NODE :
+ case Node.PROCESSING_INSTRUCTION_NODE :
+ if (contentType != CMElementDeclaration.EMPTY)
+ return;
+ error = ErrorState.INVALID_CONTENT_ERROR;
+ // Mark the whole node as an error segment.
+ segType = FMUtil.SEG_WHOLE_TAG;
+ break;
+ default :
+ error = ErrorState.INVALID_CONTENT_ERROR;
+ // Mark the whole node as an error segment.
+ segType = FMUtil.SEG_WHOLE_TAG;
+ break;
+ }
+ if (error != ErrorState.NONE_ERROR) {
+ Segment errorSeg = FMUtil.getSegment((XMLNode) child, segType);
+ if (errorSeg != null)
+ reporter.report(MessageFactory.createMessage(new ErrorInfoImpl(error, errorSeg, child)));
+ }
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLSimpleDocumentValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLSimpleDocumentValidator.java
new file mode 100644
index 0000000000..d3630a3626
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLSimpleDocumentValidator.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+import org.eclipse.wst.xml.core.internal.validate.ValidationComponent;
+
+class HTMLSimpleDocumentValidator extends CompositeValidator {
+
+ /**
+ * HTMLSimpleDocumentValidator constructor comment.
+ */
+ public HTMLSimpleDocumentValidator() {
+ super();
+
+ ValidationComponent[] validators = new ValidationComponent[2];
+
+ validators[0] = new HTMLDocumentContentValidator();
+ validators[1] = new SyntaxValidator();
+
+ register(validators);
+ }
+
+ /**
+ * Allowing the INodeAdapter to compare itself against the type
+ * allows it to return true in more than one case.
+ */
+ public boolean isAdapterForType(Object type) {
+ return ((type == HTMLSimpleDocumentValidator.class) || super.isAdapterForType(type));
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLSimpleValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLSimpleValidator.java
new file mode 100644
index 0000000000..47b6ff8f3e
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLSimpleValidator.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+import org.eclipse.wst.xml.core.internal.validate.ValidationComponent;
+
+class HTMLSimpleValidator extends CompositeValidator {
+
+ /**
+ * HTMLSimpleValidator constructor comment.
+ */
+ public HTMLSimpleValidator() {
+ super();
+
+ ValidationComponent[] validators = new ValidationComponent[5];
+
+ validators[0] = new HTMLAttributeValidator();
+ validators[1] = new HTMLElementContentValidator();
+ validators[2] = new SyntaxValidator();
+ validators[3] = new HTMLElementAncestorValidator();
+ validators[4] = new NamespaceValidator();
+
+ register(validators);
+ }
+
+ /**
+ * Allowing the INodeAdapter to compare itself against the type
+ * allows it to return true in more than one case.
+ */
+ public boolean isAdapterForType(Object type) {
+ return ((type == HTMLSimpleValidator.class) || super.isAdapterForType(type));
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLValidationAdapterFactory.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLValidationAdapterFactory.java
new file mode 100644
index 0000000000..68185c317f
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/HTMLValidationAdapterFactory.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+import org.eclipse.wst.sse.core.AbstractAdapterFactory;
+import org.eclipse.wst.sse.core.AdapterFactory;
+import org.eclipse.wst.sse.core.INodeAdapter;
+import org.eclipse.wst.sse.core.INodeNotifier;
+import org.eclipse.wst.sse.core.validate.ValidationAdapter;
+import org.w3c.dom.Node;
+
+public class HTMLValidationAdapterFactory extends AbstractAdapterFactory {
+
+ private static HTMLValidationAdapterFactory instance = null;
+
+ /**
+ * HTMLValidationAdapterFactory constructor comment.
+ */
+ public HTMLValidationAdapterFactory() {
+ super(ValidationAdapter.class, true);
+ }
+
+ /**
+ * HTMLValidationAdapterFactory constructor comment.
+ * @param adapterKey java.lang.Object
+ * @param registerAdapters boolean
+ */
+ public HTMLValidationAdapterFactory(Object adapterKey, boolean registerAdapters) {
+ super(adapterKey, registerAdapters);
+ }
+
+ /**
+ */
+ protected INodeAdapter createAdapter(INodeNotifier target) {
+ Node node = (Node) target;
+ switch (node.getNodeType()) {
+ case Node.DOCUMENT_NODE :
+ return new DocumentPropagatingValidator();
+ case Node.ELEMENT_NODE :
+ return new ElementPropagatingValidator();
+ default :
+ return new NullValidator();
+ }
+ }
+
+ /**
+ */
+ public synchronized static HTMLValidationAdapterFactory getInstance() {
+ if (instance != null)
+ return instance;
+ instance = new HTMLValidationAdapterFactory();
+ return instance;
+ }
+
+ /**
+ * Overriding Object's clone() method
+ * This is used in IModelManager's IStructuredModel copying.
+ */
+ public AdapterFactory copy() {
+ return getInstance();
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/MessageFactory.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/MessageFactory.java
new file mode 100644
index 0000000000..0419e925d5
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/MessageFactory.java
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+import java.text.MessageFormat;
+import java.util.Hashtable;
+
+import org.eclipse.wst.html.core.internal.Logger;
+import org.eclipse.wst.html.core.internal.nls.ResourceHandler;
+import org.eclipse.wst.sse.core.validate.ValidationMessage;
+import org.w3c.dom.Node;
+
+class MessageFactory implements ErrorState {
+
+
+ private static class ErrorTable {
+ private class Packet {
+ public Packet(String msg, int severity) {
+ this.msg = msg;
+ this.severity = severity;
+ }
+
+ public String getMessage() {
+ return msg;
+ }
+
+ public int getSeverity() {
+ return severity;
+ }
+
+ private String msg = null;
+ private int severity = -1;
+ }
+
+ public ErrorTable() {
+ }
+
+ public void put(int state, String msg, int severity) {
+ Packet packet = new Packet(msg, severity);
+ map.put(new Integer(state), packet);
+ }
+
+ public String getMessage(int state) {
+ return getPacket(state).getMessage();
+ }
+
+ public int getSeverity(int state) {
+ return getPacket(state).getSeverity();
+ }
+
+ private Packet getPacket(int state) {
+ return (Packet) map.get(new Integer(state));
+ }
+
+ private Hashtable map = new Hashtable();
+ }
+
+ private static interface NodeType {
+ static final int ATTRIBUTE = 0;
+ static final int ELEMENT = 1;
+ static final int DOCUMENT_TYPE = 2;
+ static final int TEXT = 3;
+ static final int COMMENT = 4;
+ static final int CDATA_SECTION = 5;
+ static final int PROCESSING_INSTRUCTION = 6;
+ static final int ENTITY_REFERENCE = 7;
+
+ static final int MAX_TYPE = 8;
+ }
+
+ // error messages
+ private static final String MSG_NO_ERROR = ResourceHandler.getString("No_error._UI_"); //$NON-NLS-1$ = "No error."
+ private static final String MSG_UNDEFINED_ATTR_ERROR = ResourceHandler.getString("Undefined_attribute_name_(_ERROR_"); //$NON-NLS-1$ = "Undefined attribute name ({0})."
+ private static final String MSG_UNDEFINED_VALUE_ERROR = ResourceHandler.getString("Undefined_attribute_value__ERROR_"); //$NON-NLS-1$ = "Undefined attribute value ({0})."
+ private static final String MSG_DUPLICATE_ATTR_ERROR = ResourceHandler.getString("Multiple_values_specified__ERROR_"); //$NON-NLS-1$ = "Multiple values specified for an attribute ({0})."
+ private static final String MSG_MISMATCHED_ATTR_ERROR = ResourceHandler.getString("Attribute_name_({0})_uses__ERROR_"); //$NON-NLS-1$ = "Attribute name ({0}) uses wrong case character."
+ private static final String MSG_INVALID_ATTR_ERROR = ResourceHandler.getString("Invalid_attribute_name_({0_ERROR_"); //$NON-NLS-1$ = "Invalid attribute name ({0})."
+ private static final String MSG_ATTR_NO_VALUE_ERROR = ResourceHandler.getString("Invalid_attribute_({0})._ERROR_"); //$NON-NLS-1$ = "Invalid attribute ({0})."
+ private static final String MSG_INVALID_CONTENT_ERROR = ResourceHandler.getString("Invalid_location_of_tag_({_ERROR_"); //$NON-NLS-1$ = "Invalid location of tag ({0})."
+ private static final String MSG_DUPLICATE_TAG_ERROR = ResourceHandler.getString("Duplicate_tag_({0})._ERROR_"); //$NON-NLS-1$ = "Duplicate tag ({0})."
+ private static final String MSG_MISSING_START_TAG_ERROR = ResourceHandler.getString("No_start_tag_(<{0}>)._ERROR_"); //$NON-NLS-1$ = "No start tag (<{0}>)."
+ private static final String MSG_MISSING_END_TAG_ERROR = ResourceHandler.getString("No_end_tag_(</{0}>)._ERROR_"); //$NON-NLS-1$ = "No end tag (</{0}>)."
+ private static final String MSG_UNNECESSARY_END_TAG_ERROR = ResourceHandler.getString("End_tag_(</{0}>)_not_neede_ERROR_"); //$NON-NLS-1$ = "End tag (</{0}>) not needed."
+ private static final String MSG_UNDEFINED_TAG_ERROR = ResourceHandler.getString("Unknown_tag_({0})._ERROR_"); //$NON-NLS-1$ = "Unknown tag ({0})."
+ private static final String MSG_MISMATCHED_TAG_ERROR = ResourceHandler.getString("Tag_name_({0})_uses_wrong__ERROR_"); //$NON-NLS-1$ = "Tag name ({0}) uses wrong case character."
+ private static final String MSG_INVALID_TAG_ERROR = ResourceHandler.getString("Invalid_tag_name_({0})._ERROR_"); //$NON-NLS-1$ = "Invalid tag name ({0})."
+ private static final String MSG_INVALID_DIRECTIVE_ERROR = ResourceHandler.getString("Invalid_JSP_directive_({0}_ERROR_"); //$NON-NLS-1$ = "Invalid JSP directive ({0})."
+ private static final String MSG_INVALID_TEXT_ERROR = ResourceHandler.getString("Invalid_text_string_({0})._ERROR_"); //$NON-NLS-1$ = "Invalid text string ({0})."
+ private static final String MSG_INVALID_CHAR_ERROR = ResourceHandler.getString("Invalid_character_used_in__ERROR_"); //$NON-NLS-1$ = "Invalid character used in text string ({0})."
+ private static final String MSG_UNKNOWN_ERROR = ResourceHandler.getString("Unknown_error._ERROR_"); //$NON-NLS-1$ = "Unknown error."
+ private static final String MSG_UNCLOSED_START_TAG_ERROR = ResourceHandler.getString("Start_tag_(<{0}>)_not_clos_ERROR_"); //$NON-NLS-1$ = "Start tag (<{0}>) not closed."
+ private static final String MSG_UNCLOSED_END_TAG_ERROR = ResourceHandler.getString("End_tag_(</{0}>)_not_close_ERROR_"); //$NON-NLS-1$ = "End tag (</{0}>) not closed."
+ private static final String MSG_UNCLOSED_TAG_ERROR = ResourceHandler.getString("Tag_({0})_not_closed._ERROR_"); //$NON-NLS-1$ = "Tag ({0}) not closed."
+ private static final String MSG_MISMATCHED_ATTR_VALUE_ERROR = ResourceHandler.getString("Attribute_value_({0})_uses_ERROR_"); //$NON-NLS-1$ = "Attribute value ({0}) uses wrong case character."
+ private static final String MSG_UNCLOSED_COMMENT_ERROR = ResourceHandler.getString("Comment_not_closed._ERROR_"); //$NON-NLS-1$ = "Comment not closed."
+ private static final String MSG_UNCLOSED_DOCTYPE_ERROR = ResourceHandler.getString("DOCTYPE_declaration_not_cl_ERROR_"); //$NON-NLS-1$ = "DOCTYPE declaration not closed."
+ private static final String MSG_UNCLOSED_PI_ERROR = ResourceHandler.getString("Processing_instruction_not_ERROR_"); //$NON-NLS-1$ = "Processing instruction not closed."
+ private static final String MSG_UNCLOSED_CDATA_SECTION_ERROR = ResourceHandler.getString("CDATA_section_not_closed._ERROR_"); //$NON-NLS-1$ = "CDATA section not closed."
+ private static final String MSG_INVALID_EMPTY_ELEMENT_TAG = ResourceHandler.getString("_ERROR_Tag_({0})_should_be_an_empty-element_tag_1"); //$NON-NLS-1$ = "Tag ({0}) should be an empty-element tag."
+ private static final String MSG_UNCLOSED_ATTR_VALUE_ERROR = ResourceHandler.getString("_ERROR_Attribute_value_({0})_not_closed._1"); //$NON-NLS-1$ ="Attribute value ({0}) not closed."
+ private static ErrorTable[] errTables = new ErrorTable[NodeType.MAX_TYPE];
+
+ static {
+ for (int i = 0; i < NodeType.MAX_TYPE; i++) {
+ errTables[i] = new ErrorTable();
+ }
+ // NOTE: The severities are just stub. They must be reviewed.
+ // -- 8/30/2001
+
+ // attribute error map
+ ErrorTable attrTable = errTables[NodeType.ATTRIBUTE];// short hand
+ attrTable.put(NONE_ERROR, MSG_NO_ERROR, 0);
+ attrTable.put(UNDEFINED_NAME_ERROR, MSG_UNDEFINED_ATTR_ERROR, ValidationMessage.WARNING);
+ attrTable.put(UNDEFINED_VALUE_ERROR, MSG_UNDEFINED_VALUE_ERROR, ValidationMessage.WARNING);
+ attrTable.put(MISMATCHED_ERROR, MSG_MISMATCHED_ATTR_ERROR, ValidationMessage.WARNING);
+ attrTable.put(INVALID_NAME_ERROR, MSG_INVALID_ATTR_ERROR, ValidationMessage.WARNING);
+ attrTable.put(INVALID_ATTR_ERROR, MSG_ATTR_NO_VALUE_ERROR, ValidationMessage.WARNING);
+ attrTable.put(DUPLICATE_ERROR, MSG_DUPLICATE_ATTR_ERROR, ValidationMessage.WARNING);
+ attrTable.put(MISMATCHED_VALUE_ERROR, MSG_MISMATCHED_ATTR_VALUE_ERROR, ValidationMessage.ERROR);
+ //<<D210422
+ attrTable.put(UNCLOSED_ATTR_VALUE, MSG_UNCLOSED_ATTR_VALUE_ERROR, ValidationMessage.WARNING);
+ //D210422
+ // element error map
+ ErrorTable elemTable = errTables[NodeType.ELEMENT];// short hand
+ elemTable.put(NONE_ERROR, MSG_NO_ERROR, 0);
+ elemTable.put(UNDEFINED_NAME_ERROR, MSG_UNDEFINED_TAG_ERROR, ValidationMessage.WARNING);
+ elemTable.put(INVALID_NAME_ERROR, MSG_INVALID_TAG_ERROR, ValidationMessage.ERROR);
+ elemTable.put(MISMATCHED_ERROR, MSG_MISMATCHED_TAG_ERROR, ValidationMessage.WARNING);
+ elemTable.put(MISMATCHED_END_TAG_ERROR, MSG_MISMATCHED_TAG_ERROR, ValidationMessage.ERROR);
+ elemTable.put(MISSING_START_TAG_ERROR, MSG_MISSING_START_TAG_ERROR, ValidationMessage.ERROR);
+ elemTable.put(MISSING_END_TAG_ERROR, MSG_MISSING_END_TAG_ERROR, ValidationMessage.WARNING);
+ elemTable.put(UNNECESSARY_END_TAG_ERROR, MSG_UNNECESSARY_END_TAG_ERROR, ValidationMessage.WARNING);
+ elemTable.put(INVALID_DIRECTIVE_ERROR, MSG_INVALID_DIRECTIVE_ERROR, ValidationMessage.ERROR);
+ elemTable.put(INVALID_CONTENT_ERROR, MSG_INVALID_CONTENT_ERROR, ValidationMessage.WARNING);
+ elemTable.put(DUPLICATE_ERROR, MSG_DUPLICATE_TAG_ERROR, ValidationMessage.WARNING);
+ elemTable.put(COEXISTENCE_ERROR, MSG_INVALID_CONTENT_ERROR, ValidationMessage.WARNING);
+ elemTable.put(UNCLOSED_TAG_ERROR, MSG_UNCLOSED_START_TAG_ERROR, ValidationMessage.ERROR);
+ elemTable.put(UNCLOSED_END_TAG_ERROR, MSG_UNCLOSED_END_TAG_ERROR, ValidationMessage.ERROR);
+ elemTable.put(INVALID_EMPTY_ELEMENT_TAG, MSG_INVALID_EMPTY_ELEMENT_TAG, ValidationMessage.WARNING);
+
+ // document type error map
+ ErrorTable docTable = errTables[NodeType.DOCUMENT_TYPE];// short hand
+ docTable.put(NONE_ERROR, MSG_NO_ERROR, 0);
+ docTable.put(DUPLICATE_ERROR, MSG_DUPLICATE_TAG_ERROR, ValidationMessage.ERROR);
+ docTable.put(INVALID_CONTENT_ERROR, MSG_INVALID_CONTENT_ERROR, ValidationMessage.WARNING);
+ docTable.put(UNCLOSED_TAG_ERROR, MSG_UNCLOSED_DOCTYPE_ERROR, ValidationMessage.ERROR);
+
+ // text error map
+ ErrorTable textTable = errTables[NodeType.TEXT];
+ textTable.put(NONE_ERROR, MSG_NO_ERROR, 0);
+ textTable.put(INVALID_CONTENT_ERROR, MSG_INVALID_TEXT_ERROR, ValidationMessage.WARNING);
+ textTable.put(INVALID_CHAR_ERROR, MSG_INVALID_CHAR_ERROR, ValidationMessage.WARNING);
+
+ // comment error map
+ ErrorTable commTable = errTables[NodeType.COMMENT];
+ commTable.put(NONE_ERROR, MSG_NO_ERROR, 0);
+ commTable.put(INVALID_CONTENT_ERROR, MSG_INVALID_CONTENT_ERROR, ValidationMessage.WARNING);
+ commTable.put(UNCLOSED_TAG_ERROR, MSG_UNCLOSED_COMMENT_ERROR, ValidationMessage.ERROR);
+
+ // cdata section error map
+ ErrorTable cdatTable = errTables[NodeType.CDATA_SECTION];
+ cdatTable.put(NONE_ERROR, MSG_NO_ERROR, 0);
+ cdatTable.put(INVALID_CONTENT_ERROR, MSG_INVALID_CONTENT_ERROR, ValidationMessage.WARNING);
+ cdatTable.put(UNCLOSED_TAG_ERROR, MSG_UNCLOSED_CDATA_SECTION_ERROR, ValidationMessage.ERROR);
+
+ // processing instruction error map
+ ErrorTable piTable = errTables[NodeType.PROCESSING_INSTRUCTION];
+ piTable.put(NONE_ERROR, MSG_NO_ERROR, 0);
+ piTable.put(INVALID_CONTENT_ERROR, MSG_INVALID_CONTENT_ERROR, ValidationMessage.WARNING);
+ piTable.put(UNCLOSED_TAG_ERROR, MSG_UNCLOSED_PI_ERROR, ValidationMessage.ERROR);
+
+ // entity reference error map
+ ErrorTable erTable = errTables[NodeType.ENTITY_REFERENCE];
+ erTable.put(NONE_ERROR, MSG_NO_ERROR, 0);
+ erTable.put(UNDEFINED_NAME_ERROR, MSG_UNDEFINED_TAG_ERROR, ValidationMessage.WARNING);
+ erTable.put(INVALID_CONTENT_ERROR, MSG_INVALID_CONTENT_ERROR, ValidationMessage.WARNING);
+ }
+
+ /**
+ */
+ public static ValidationMessage createMessage(ErrorInfo info) {
+ String errorMsg = getErrorMessage(info);
+ int errorSeverity = getErrorSeverity(info);
+ return new ValidationMessage(errorMsg, info.getOffset(), info.getLength(), errorSeverity);
+ }
+
+ private static String getErrorMessage(ErrorInfo info) {
+ ErrorTable tab = getErrorTable(info.getTargetType());
+ if (tab == null)
+ return MSG_UNKNOWN_ERROR;
+
+ String template = tab.getMessage(info.getState());
+ Object[] arguments = {info.getHint()};
+ String s = null;
+ try {
+ s = MessageFormat.format(template, arguments);
+ }
+ catch (IllegalArgumentException e) {
+ Logger.logException(e);
+ s = template + ":" + arguments.toString(); //$NON-NLS-1$
+ }
+ return s;
+ }
+
+ /**
+ */
+ private static int getErrorSeverity(ErrorInfo info) {
+ ErrorTable tab = getErrorTable(info.getTargetType());
+ if (tab == null)
+ return 0;
+ return tab.getSeverity(info.getState());
+ }
+
+ private static ErrorTable getErrorTable(short nodetype) {
+ ErrorTable tab = null;
+ switch (nodetype) {
+ case Node.ATTRIBUTE_NODE :
+ tab = errTables[NodeType.ATTRIBUTE];
+ break;
+ case Node.ELEMENT_NODE :
+ tab = errTables[NodeType.ELEMENT];
+ break;
+ case Node.DOCUMENT_TYPE_NODE :
+ tab = errTables[NodeType.DOCUMENT_TYPE];
+ break;
+ case Node.TEXT_NODE :
+ tab = errTables[NodeType.TEXT];
+ break;
+ case Node.COMMENT_NODE :
+ tab = errTables[NodeType.COMMENT];
+ break;
+ case Node.CDATA_SECTION_NODE :
+ tab = errTables[NodeType.CDATA_SECTION];
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE :
+ tab = errTables[NodeType.PROCESSING_INSTRUCTION];
+ break;
+ case Node.ENTITY_REFERENCE_NODE :
+ tab = errTables[NodeType.ENTITY_REFERENCE];
+ break;
+ default :
+ return null;
+ }
+ return tab;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/NamespaceValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/NamespaceValidator.java
new file mode 100644
index 0000000000..f2e605da44
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/NamespaceValidator.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.common.contentmodel.CMNamedNodeMap;
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.document.XMLAttr;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+public class NamespaceValidator extends PrimeValidator implements ErrorState {
+
+ private final static String XMLNS_PREFIX = "xmlns";//$NON-NLS-1$
+ private final static String NS_SEPARATOR = ":";//$NON-NLS-1$
+
+ public NamespaceValidator() {
+ super();
+ }
+
+ public boolean isAdapterForType(Object type) {
+ return ((type == NamespaceValidator.class) || super.isAdapterForType(type));
+ }
+
+ public void validate(IndexedRegion node) {
+ Element target = (Element) node;
+ if (isXMLElement(target) && hasUnknownPrefix(target)) {
+ XMLElement e = (XMLElement) target;
+ if (!isValidPrefix(e.getPrefix(), target) && !e.isCommentTag()) {
+ // report unknown tag error.
+ Segment errorSeg = FMUtil.getSegment(e, FMUtil.SEG_START_TAG);
+ if (errorSeg != null)
+ reporter.report(MessageFactory.createMessage(new ErrorInfoImpl(UNDEFINED_NAME_ERROR, errorSeg, e)));
+ }
+ }
+ // (2) check prefix of each attr
+ NamedNodeMap attrs = target.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Node n = attrs.item(i);
+ if (!(n instanceof XMLAttr))
+ continue;
+ XMLAttr a = (XMLAttr) n;
+ String prefix = a.getPrefix();
+ if ((prefix != null) && isUnknownAttr(a, target)) {
+ // The attr has unknown prefix. So, check it.
+ if (!isValidPrefix(prefix, target)) {
+ // report unknown attr error.
+ ITextRegion r = a.getNameRegion();
+ if (r == null)
+ continue;
+ int a_offset = a.getNameRegionStartOffset();
+ int a_length = a.getNameRegion().getLength();
+ reporter.report(MessageFactory.createMessage(new ErrorInfoImpl(UNDEFINED_NAME_ERROR, new Segment(a_offset, a_length), a)));
+ }
+ }
+ }
+ }
+
+ // private methods
+ private boolean isXMLElement(Element target) {
+ return target instanceof XMLElement;
+ }
+
+ private boolean hasUnknownPrefix(Element target) {
+ return isUnknownElement(target) && CMUtil.isForeign(target);
+ }
+
+ private boolean isUnknownElement(Element target) {
+ CMElementDeclaration dec = CMUtil.getDeclaration(target);
+ return dec == null;
+ }
+
+ private boolean isUnknownAttr(XMLAttr attr, Element target) {
+ CMElementDeclaration dec = CMUtil.getDeclaration(target);
+ if (dec == null)
+ return true; // unknown.
+ CMNamedNodeMap adecls = dec.getAttributes();
+ CMAttributeDeclaration adec = (CMAttributeDeclaration) adecls.getNamedItem(attr.getName());
+ return adec == null;
+ }
+
+ private boolean isValidPrefix(String prefix, Element e) {
+ if (prefix.equals(XMLNS_PREFIX))
+ return true; // "xmlns:foo" attr is always valid.
+
+ // (1) check the element has the namespace definition or not.
+ if (isValidPrefixWithinElement(prefix, e))
+ return true;
+
+ // (2) check ancestors of the element have the namespace definition or not.
+ Element parent = SMUtil.getParentElement(e);
+ while (parent != null) {
+ if (isValidPrefixWithinElement(prefix, parent))
+ return true;
+ parent = SMUtil.getParentElement(parent);
+ }
+ return false;
+ }
+
+ private boolean isValidPrefixWithinElement(String prefix, Element e) {
+ String ns = XMLNS_PREFIX + NS_SEPARATOR + prefix;
+ NamedNodeMap attrs = e.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Node n = attrs.item(i);
+ if (n == null)
+ continue;
+ if (n.getNodeType() != Node.ATTRIBUTE_NODE)
+ continue;
+ if (ns.equals(((Attr) n).getName()))
+ return true;
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/NullValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/NullValidator.java
new file mode 100644
index 0000000000..1a9cbc0e7a
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/NullValidator.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.sse.core.validate.ValidationReporter;
+import org.eclipse.wst.xml.core.internal.validate.ValidationComponent;
+
+/**
+ * NullValidator class is intended to be a replacement of null
+ * for ValidationComponent type.
+ */
+final class NullValidator extends ValidationComponent {
+
+ public NullValidator() {
+ super();
+ }
+
+ public void validate(IndexedRegion node) {
+ return;
+ }
+
+ public void setReporter(ValidationReporter reporter) {
+ return;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/PrimeValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/PrimeValidator.java
new file mode 100644
index 0000000000..6278a3ab23
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/PrimeValidator.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+import org.eclipse.wst.xml.core.internal.validate.ValidationComponent;
+
+abstract class PrimeValidator extends ValidationComponent {
+
+ /**
+ * PrimeValidator constructor comment.
+ */
+ public PrimeValidator() {
+ super();
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/SMUtil.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/SMUtil.java
new file mode 100644
index 0000000000..97adcf80fc
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/SMUtil.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+final class SMUtil {
+
+ private SMUtil() {
+ super();
+ }
+
+ /* get an ancestor element ignoring implicit ones. */
+ public static Element getParentElement(Node child) {
+ if (child == null)
+ return null;
+
+ Node p = child.getParentNode();
+ while (p != null) {
+ if (p.getNodeType() == Node.ELEMENT_NODE) {
+ return (Element) p;
+ }
+ p = p.getParentNode();
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/Segment.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/Segment.java
new file mode 100644
index 0000000000..2e5db726e5
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/Segment.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+
+public class Segment {
+
+ private int offset = 0;
+ private int length = 0;
+
+ /**
+ */
+ public Segment(int offset, int length) {
+ super();
+ this.offset = offset;
+ this.length = length;
+ }
+
+ public Segment(IStructuredDocumentRegion region) {
+ super();
+ this.offset = region.getStartOffset();
+ this.length = region.getLength();
+ }
+
+ /**
+ * NOTE: 'start' and 'end' must be the start and end of the contiguous regions.
+ * Otherwise, this class cannot work correctly.
+ */
+ public Segment(IStructuredDocumentRegion start, IStructuredDocumentRegion end) {
+ super();
+ this.offset = start.getStartOffset();
+ int endOffset = (end == null) ? start.getEndOffset() : end.getEndOffset();
+ this.length = endOffset - this.offset;
+ }
+
+ //public Segment(ITextRegion start, ITextRegion end) {
+ // super();
+ // this.offset = start.getStartOffset();
+ // int endOffset = (end == null) ? start.getEndOffset() : end.getEndOffset();
+ // this.length = endOffset - this.offset;
+ //}
+ /**
+ */
+ public int getLength() {
+ return this.length;
+ }
+
+ /**
+ */
+ public int getOffset() {
+ return this.offset;
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/SyntaxValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/SyntaxValidator.java
new file mode 100644
index 0000000000..01b217727e
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/validate/SyntaxValidator.java
@@ -0,0 +1,345 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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.wst.html.core.validate;
+
+import java.util.Iterator;
+
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.html.core.document.HTMLDocumentTypeEntry;
+import org.eclipse.wst.html.core.document.HTMLDocumentTypeRegistry;
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.document.InvalidCharacterException;
+import org.eclipse.wst.xml.core.document.XMLDocument;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.eclipse.wst.xml.core.internal.document.SourceValidator;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+class SyntaxValidator extends PrimeValidator implements ErrorState {
+
+
+ static private boolean isValidRegion(ITextRegion rgn) {
+ String type = rgn.getType();
+ if (type == null)
+ return false; // no type is invalid.
+ if (type == XMLRegionContext.XML_END_TAG_OPEN || type == XMLRegionContext.XML_TAG_NAME || type == XMLRegionContext.XML_TAG_CLOSE) {
+ return true;
+ }
+ return false;
+ }
+
+ static private String getTagName(IStructuredDocumentRegion tag) {
+ ITextRegionList regions = tag.getRegions();
+ Iterator iter = regions.iterator();
+ while (iter.hasNext()) {
+ ITextRegion rgn = (ITextRegion) iter.next();
+ if (rgn.getType() == XMLRegionContext.XML_TAG_NAME)
+ return tag.getText(rgn);
+ }
+ return "";//$NON-NLS-1$
+ }
+
+ static private boolean isEmptyContent(CMElementDeclaration decl) {
+ return (decl != null) && (decl.getContentType() == CMElementDeclaration.EMPTY);
+ }
+
+ public SyntaxValidator() {
+ super();
+ }
+
+ public boolean isAdapterForType(Object type) {
+ return ((type == SyntaxValidator.class) || super.isAdapterForType(type));
+ }
+
+ class ElementInfo {
+ public ElementInfo() {
+ super();
+ }
+
+ public XMLElement target = null;
+ public CMElementDeclaration decl = null;
+ public IStructuredDocumentRegion startTag = null;
+ public IStructuredDocumentRegion endTag = null;
+ public boolean hasStartTag = false;
+ public boolean hasEndTag = false;
+ public boolean isXHTML = false;
+ }
+
+ public void validate(IndexedRegion indexedNode) {
+ Node node = (Node) indexedNode;
+ validateChildren(node);
+
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ return;
+ if (!(node instanceof XMLElement))
+ return;
+
+ ElementInfo info = new ElementInfo();
+ info.target = (XMLElement) node;
+
+ // gather information to validate from target at once.
+ getInfo(info);
+
+ if (info.target.isGlobalTag()) {
+ validateTags(info);
+ validateNames(info);
+ if (info.decl != null && info.isXHTML) {
+ validateTagCase(info);
+ }
+ }
+ }
+
+ private void getInfo(ElementInfo info) {
+ info.decl = CMUtil.getDeclaration(info.target);
+ info.startTag = info.target.getStartStructuredDocumentRegion();
+ info.endTag = info.target.getEndStructuredDocumentRegion();
+
+ info.hasStartTag = (info.startTag != null);
+ info.hasEndTag = (info.endTag != null);
+
+ Document doc = info.target.getOwnerDocument();
+ if (!(doc instanceof XMLDocument))
+ return;
+ String typeid = ((XMLDocument) doc).getDocumentTypeId();
+ if (typeid != null) {
+ HTMLDocumentTypeEntry entry = HTMLDocumentTypeRegistry.getInstance().getEntry(typeid);
+ info.isXHTML = (entry != null && entry.isXMLType());
+ }
+ }
+
+ class TagErrorInfoImpl extends AbstractErrorInfo {
+ private String hint = null;
+
+ public TagErrorInfoImpl(int state, IStructuredDocumentRegion tag, String hint) {
+ super(state, new Segment(tag));
+ this.hint = hint;
+ }
+
+ public String getHint() {
+ return hint;
+ }
+
+ public short getTargetType() {
+ return Node.ELEMENT_NODE;
+ }
+ }
+
+ private boolean isEndTagCorrupted(ElementInfo info) {
+ ITextRegionList regions = info.endTag.getRegions();
+ if (regions == null || regions.isEmpty())
+ return false;
+ Iterator iter = regions.iterator();
+ while (iter.hasNext()) {
+ ITextRegion rgn = (ITextRegion) iter.next();
+ if (!isValidRegion(rgn))
+ return true; // found invalid region type.
+ }
+ return false; // all regions are valid.
+ }
+
+ private String getEndTagFullText(ElementInfo info) {
+ String hint = "";//$NON-NLS-1$
+ ITextRegionList regions = info.endTag.getRegions();
+ Iterator iter = regions.iterator();
+ while (iter.hasNext()) {
+ ITextRegion rgn = (ITextRegion) iter.next();
+ String type = rgn.getType();
+ if (type == null)
+ continue;
+ if (type == XMLRegionContext.XML_END_TAG_OPEN || type == XMLRegionContext.XML_TAG_CLOSE)
+ continue;
+ hint += info.endTag.getFullText(rgn);
+ }
+ return hint;
+ }
+
+ private void reportCorruptedEndTagError(ElementInfo info) {
+ String hint = getEndTagFullText(info);
+ TagErrorInfoImpl error = new TagErrorInfoImpl(UNDEFINED_NAME_ERROR, info.endTag, hint);
+ this.reporter.report(MessageFactory.createMessage(error));
+ }
+
+ private void validateTags(ElementInfo info) {
+ if (info.hasStartTag) {
+ if (!info.target.isStartTagClosed()) {
+ // Mark the whole START tag as an error segment.
+ Segment errorSeg = new Segment(info.startTag);
+ report(UNCLOSED_TAG_ERROR, errorSeg, info.target);
+ }
+ }
+ else {
+ if (info.hasEndTag) {
+ if (info.decl != null) {
+ if (CMUtil.isHTML(info.decl) && !info.target.hasChildNodes()) {
+ if (info.target.isContainer()) {
+ // Set the error mark to the start of the element.
+ Segment errorSeg = new Segment(info.target.getStartOffset(), 0);
+ report(MISSING_START_TAG_ERROR, errorSeg, info.target);
+ }
+ else {
+ // Mark the whole END tag as an error segment.
+ Segment errorSeg = new Segment(info.endTag);
+ report(UNNECESSARY_END_TAG_ERROR, errorSeg, info.target);
+ }
+ }
+ else if (info.isXHTML) {
+ Segment errorSeg = new Segment(info.target.getStartOffset(), 0);
+ report(MISSING_START_TAG_ERROR, errorSeg, info.target);
+ }
+ }
+ }
+ }
+
+ if (info.hasEndTag) {
+ if (!info.target.isClosed()) {
+ // Set the whole END tag as error segment.
+ Segment errorSeg = new Segment(info.endTag);
+ report(UNCLOSED_END_TAG_ERROR, errorSeg, info.target);
+ }
+ }
+ else {
+ if (info.isXHTML) { // XHTML
+ if (!info.target.isEmptyTag()) {
+ if (isEmptyContent(info.decl)) {
+ // EMPTY element should be written in <.../> form.
+ Segment errorSeg = FMUtil.getSegment(info.target, FMUtil.SEG_START_TAG);
+ report(INVALID_EMPTY_ELEMENT_TAG, errorSeg, info.target);
+ }
+ else {
+ // end tag is required.
+ Segment errorSeg = new Segment(info.target.getEndOffset(), 0);
+ report(MISSING_END_TAG_ERROR, errorSeg, info.target);
+ }
+ }
+ }
+ else { // HTML
+ if (info.hasStartTag) {
+ if (info.decl != null && CMUtil.isHTML(info.decl) && !info.target.isEmptyTag() && !CMUtil.isEndTagOmissible(info.decl)) {
+ // Set the error mark to the end of the element.
+ Segment errorSeg = new Segment(info.target.getEndOffset(), 0);
+ report(MISSING_END_TAG_ERROR, errorSeg, info.target);
+ }
+ }
+ }
+ }
+ }
+
+ /* perform validation about tag name definition. */
+ private void validateNames(ElementInfo info) {
+ boolean corrupted = info.hasEndTag && isEndTagCorrupted(info);
+ if (info.decl == null) {
+ // If no declaration is retrieved, the target is really
+ // unknown element.
+ if (!info.hasStartTag && corrupted) {
+ reportCorruptedEndTagError(info);
+ }
+ else {
+ Segment errorSeg = FMUtil.getSegment(info.target, FMUtil.SEG_START_TAG);
+ report(UNDEFINED_NAME_ERROR, errorSeg, info.target);
+ }
+ }
+ else {
+ // Even if a declaration could be retrieved, if the end
+ // tag is corrupted, it should be reported as undefined
+ // name. (D202493)
+ if (corrupted) {
+ reportCorruptedEndTagError(info);
+ }
+ }
+ }
+
+ /* perform validation tag case only for XHTML document */
+ private void validateTagCase(ElementInfo info) {
+ String declared = info.decl.getElementName();
+ String startTagName = "";//$NON-NLS-1$
+ String endTagName = "";//$NON-NLS-1$
+ if (declared == null)
+ return;
+
+ // start tag
+ if (info.hasStartTag) {
+ startTagName = getTagName(info.startTag);
+ if (!declared.equals(startTagName)) {
+ TagErrorInfoImpl error = new TagErrorInfoImpl(MISMATCHED_ERROR, info.startTag, startTagName);
+ this.reporter.report(MessageFactory.createMessage(error));
+ }
+ }
+ // end tag
+ if (info.hasEndTag) {
+ endTagName = getTagName(info.endTag);
+ if (!info.hasStartTag || (!endTagName.equals(startTagName))) {
+ if (!declared.equals(endTagName)) {
+ TagErrorInfoImpl error = new TagErrorInfoImpl(MISMATCHED_ERROR, info.endTag, endTagName);
+ this.reporter.report(MessageFactory.createMessage(error));
+ }
+ }
+ }
+ }
+
+ private void validateChildren(Node target) {
+ if ((target.getNodeType() == Node.ELEMENT_NODE) && CMUtil.isForeign((Element) target))
+ return;
+
+ for (Node child = target.getFirstChild(); child != null; child = child.getNextSibling()) {
+ switch (child.getNodeType()) {
+ case Node.TEXT_NODE :
+ {
+ XMLNode text = (XMLNode) child;
+ int charOffset = validateTextSource(text);
+ if (charOffset >= 0) {
+ charOffset += text.getStartOffset();
+ Segment errorSeg = new Segment(charOffset, 1);
+ if (errorSeg != null)
+ report(INVALID_CHAR_ERROR, errorSeg, text);
+ }
+ break;
+ }
+ case Node.COMMENT_NODE :
+ case Node.DOCUMENT_TYPE_NODE :
+ case Node.PROCESSING_INSTRUCTION_NODE :
+ case Node.CDATA_SECTION_NODE :
+ {
+ XMLNode tag = (XMLNode) child;
+ if (!tag.isClosed()) {
+ Segment errorSeg = FMUtil.getSegment(tag, FMUtil.SEG_WHOLE_TAG);
+ if (errorSeg != null)
+ report(UNCLOSED_TAG_ERROR, errorSeg, tag);
+ }
+ break;
+ }
+ default :
+ break;
+ }
+ }
+ }
+
+ private int validateTextSource(XMLNode text) {
+ try {
+ SourceValidator validator = new SourceValidator(text);
+ validator.validateSource(text.getSource());
+ }
+ catch (InvalidCharacterException ex) {
+ return ex.getOffset();
+ }
+ return -1;
+ }
+
+ private void report(int state, Segment errorSeg, Node node) {
+ ErrorInfo info = new ErrorInfoImpl(state, errorSeg, node);
+ reporter.report(MessageFactory.createMessage(info));
+ }
+} \ No newline at end of file

Back to the top