diff options
Diffstat (limited to 'bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/document/HTMLModelParserAdapter.java')
-rw-r--r-- | bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/document/HTMLModelParserAdapter.java | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/document/HTMLModelParserAdapter.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/document/HTMLModelParserAdapter.java new file mode 100644 index 0000000000..e8b4fb3593 --- /dev/null +++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/document/HTMLModelParserAdapter.java @@ -0,0 +1,354 @@ +/******************************************************************************* + * 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.document; + + + +import org.eclipse.wst.common.contentmodel.CMContent; +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.html.core.HTML40Namespace; +import org.eclipse.wst.html.core.HTMLCMProperties; +import org.eclipse.wst.html.core.contentmodel.HTMLElementDeclaration; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.xml.core.document.TagAdapter; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLText; +import org.eclipse.wst.xml.core.internal.document.CMNodeUtil; +import org.eclipse.wst.xml.core.internal.document.ModelParserAdapter; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * HTMLDocumentImpl class + */ +public class HTMLModelParserAdapter implements ModelParserAdapter { + /** + * note: I made public, temparily, so could be used by JSPLoader + */ + protected HTMLModelParserAdapter() { + super(); + } + + private boolean shouldTerminateAt(CMElementDeclaration parent, CMElementDeclaration child) { + if (!parent.supports(HTMLCMProperties.TERMINATORS)) + return false; + java.util.Iterator i = (java.util.Iterator) parent.getProperty(HTMLCMProperties.TERMINATORS); + if (i == null) + return false; + String nextName = child.getElementName(); + while (i.hasNext()) { + // NOTE: CMElementDeclaration of child is not always HTMLCMElementDeclaration. + // It might be one of based on DTD (for XHTML element). So, comparison must + // be performed ignoring case. + // -- 3/20/2002 + String terminator = (String) i.next(); + if (terminator == null) + continue; + if (nextName.equalsIgnoreCase(terminator)) + return true; + } + return false; + } + + /** + */ + public boolean canContain(Element element, Node child) { + if (element == null || child == null) + return false; + XMLElement impl = (XMLElement) element; + + if (child.getNodeType() == Node.ELEMENT_NODE) { + if (!impl.isGlobalTag()) + return true; // non HTML tag + XMLElement childElement = (XMLElement) child; + + CMElementDeclaration myDec = CMNodeUtil.getElementDeclaration(element); + if (myDec == null) + return true; + //if (!(myDec instanceof HTMLElementDeclaration)) return true; + if (myDec.getContentType() == CMElementDeclaration.EMPTY) + return false; + + if (!childElement.isGlobalTag()) + return true; // non HTML tag + CMElementDeclaration childDec = CMNodeUtil.getElementDeclaration(childElement); + if (childDec == null) + return true; + //if (!(childDec instanceof HTMLElementDeclaration)) return true; + + if (myDec instanceof HTMLElementDeclaration) { + if (((Boolean) ((HTMLElementDeclaration) myDec).getProperty(HTMLCMProperties.IS_JSP)).booleanValue()) + return true; + } + if (shouldTerminateAt(myDec, childDec) && !isValidChild(myDec, childDec)) { + return false; + } + + String tagName = impl.getTagName(); + if (tagName == null) + return true; + String childName = childElement.getTagName(); + if (childName == null) + return true; + if (!impl.hasStartTag() && !impl.hasEndTag()) { + // implicit element + if (tagName.equalsIgnoreCase(childElement.getTagName())) + return false; + if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HEAD)) { + if (!childName.equalsIgnoreCase(HTML40Namespace.ElementName.META) && !childName.equalsIgnoreCase(HTML40Namespace.ElementName.TITLE) && !childName.equalsIgnoreCase(HTML40Namespace.ElementName.LINK) && !childName.equalsIgnoreCase(HTML40Namespace.ElementName.STYLE) && !childName.equalsIgnoreCase(HTML40Namespace.ElementName.BASE) && !childName.equalsIgnoreCase(HTML40Namespace.ElementName.ISINDEX)) { + return false; + } + } + + Node parent = element.getParentNode(); + if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) { + XMLElement parentElement = (XMLElement) parent; + if (!parentElement.hasStartTag() && !parentElement.hasEndTag()) { + if (!canContain(parentElement, child)) + return false; + } + } + return true; + } + + // contexual termination for TABLE content tags + boolean isTableContent = false; + if (childName.equalsIgnoreCase(HTML40Namespace.ElementName.TBODY) || childName.equalsIgnoreCase(HTML40Namespace.ElementName.THEAD) || childName.equalsIgnoreCase(HTML40Namespace.ElementName.TFOOT)) { + if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.TABLE)) + return true; + isTableContent = true; + } + else if (childName.equalsIgnoreCase(HTML40Namespace.ElementName.TR)) { + if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.TBODY) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.THEAD) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.TFOOT) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.TABLE)) + return true; + isTableContent = true; + } + else if (childName.equalsIgnoreCase(HTML40Namespace.ElementName.TD) || childName.equalsIgnoreCase(HTML40Namespace.ElementName.TH)) { + if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.TR) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.TBODY) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.THEAD) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.TFOOT) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.TABLE)) + return true; + isTableContent = true; + } + if (isTableContent) { + // TABLE content tags should terminate non TABLE content tags, + // if in TABLE + for (Node parent = element.getParentNode(); parent != null; parent = parent.getParentNode()) { + if (parent.getNodeType() != Node.ELEMENT_NODE) + break; + XMLElement parentElement = (XMLElement) parent; + String parentName = parentElement.getTagName(); + if (parentName == null) + continue; + if (parentName.equalsIgnoreCase(HTML40Namespace.ElementName.TABLE)) + return false; + } + } + if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.EMBED)) { + if (!childName.equalsIgnoreCase(HTML40Namespace.ElementName.NOEMBED)) + return false; + } + } + else if (child.getNodeType() == Node.TEXT_NODE) { + String tagName = impl.getTagName(); + if (tagName != null && tagName.equalsIgnoreCase(HTML40Namespace.ElementName.EMBED)) { + XMLText text = (XMLText) child; + if (!text.isWhitespace()) + return false; + } + } + else if (child.getNodeType() == Node.DOCUMENT_TYPE_NODE) { + if (impl.isImplicitTag()) + return false; + } + + return true; + } + + /** + */ + public boolean canBeImplicitTag(Element element) { + return false; + } + + /** + */ + public boolean canBeImplicitTag(Element element, Node child) { + return false; + } + + /** + */ + public Element createCommentElement(Document document, String data, boolean isJSPTag) { + if (document == null || data == null || data.length() == 0) + return null; + + return createMetaElement(document, data, isJSPTag); + } + + /** + * This routine create an implicit Element for given parent and child, + * such as HTML, BODY, HEAD, and TBODY for HTML document. + */ + public Element createImplicitElement(Document document, Node parent, Node child) { + return null; + } + + /** + */ + private Element createMetaElement(Document document, String data, boolean isJSPTag) { + if (data == null || data.length() == 0) + return null; + + TagScanner scanner = new TagScanner(data, 0, true); // one line + String name = scanner.nextName(); + if (name == null || !name.equalsIgnoreCase(MetaData.METADATA)) + return null; + + String type = null; + boolean isStartSpan = false; + boolean isEndSpan = false; + name = scanner.nextName(); + while (name != null) { + String value = scanner.nextValue(); + if (name.equalsIgnoreCase(MetaData.TYPE)) { + if (value == null) + return null; + if (value.equalsIgnoreCase(MetaData.DESIGNER_CONTROL)) { + type = MetaData.DESIGNER_CONTROL; + } + else if (value.equalsIgnoreCase(MetaData.DYNAMIC_DATA)) { + type = MetaData.DYNAMIC_DATA; + } + else if (value.equalsIgnoreCase(MetaData.AUTHOR_TIME_VISUAL)) { + type = MetaData.AUTHOR_TIME_VISUAL; + } + else if (value.equalsIgnoreCase(MetaData.ANNOTATION)) { + type = MetaData.ANNOTATION; + } + else { + return null; + } + } + else if (name.equalsIgnoreCase(MetaData.STARTSPAN)) { + isStartSpan = true; + } + else if (name.equalsIgnoreCase(MetaData.ENDSPAN)) { + if (!isStartSpan) + isEndSpan = true; + } + name = scanner.nextName(); + } + if (type == null) + return null; + if (!isStartSpan && !isEndSpan) + return null; + String metaData = null; + int offset = scanner.getNextOffset(); // skip new line + if (offset < data.length()) + metaData = data.substring(offset); + if (metaData == null) + metaData = new String(); + + XMLElement element = (XMLElement) document.createElement(MetaData.PREFIX + type); + + MetaDataAdapter adapter = new MetaDataAdapter(type); + if (isStartSpan) { + if (metaData != null) + adapter.setData(metaData); + } + else { + if (metaData != null) + adapter.setEndData(metaData); + } + element.addAdapter(adapter); + adapter.setElement(element); + element.setJSPTag(isJSPTag); + + return element; + } + + /** + */ + public String getFindRootName(String tagName) { + if (tagName == null) + return null; + // tag matching should not beyond TABLE tag except BODY tag + if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.BODY)) + return null; + return HTML40Namespace.ElementName.TABLE; + } + + /** + */ + public boolean isAdapterForType(Object type) { + return (type == ModelParserAdapter.class); + } + + /** + */ + public boolean isEndTag(XMLElement element) { + TagAdapter adapter = (TagAdapter) element.getExistingAdapter(TagAdapter.class); + if (adapter != null) + return adapter.isEndTag(); + return element.isEndTag(); + } + + /** + */ + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + } + + private static boolean isValidChild(CMElementDeclaration parent, CMElementDeclaration child) { + if (parent == null || child == null) + return false; + CMContent content = parent.getContent(); + if (content == null) + return false; + return isChild(content, child); + } + + /** + */ + private static boolean isChild(CMContent content, CMElementDeclaration target) { + switch (content.getNodeType()) { + case CMNode.ELEMENT_DECLARATION : + 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 (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; + } + + /** + */ + private static boolean isSameDeclaration(CMElementDeclaration aDec, CMElementDeclaration otherDec) { + return aDec.getElementName() == otherDec.getElementName(); + } + +}
\ No newline at end of file |