/******************************************************************************* * Copyright (c) 2002, 2006 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 * Jens Lukowski/Innoopract - initial renaming/restructuring * *******************************************************************************/ package org.eclipse.wst.xml.core.internal.contentmodel.internal.util; import java.util.Iterator; import java.util.List; import java.util.Vector; import org.eclipse.wst.xml.core.internal.contentmodel.CMAnyElement; import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument; import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration; import org.eclipse.wst.xml.core.internal.contentmodel.CMGroup; import org.eclipse.wst.xml.core.internal.contentmodel.CMNode; import org.eclipse.wst.xml.core.internal.contentmodel.CMNodeList; import org.eclipse.wst.xml.core.internal.contentmodel.util.CMVisitor; import org.eclipse.wst.xml.core.internal.contentmodel.util.DOMNamespaceHelper; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.Text; /** * A special CMValidator that knows about DOMs */ public class DOMValidator extends CMValidator { protected String getNamespaceURI(Node node) { return DOMNamespaceHelper.getNamespaceURI(node); //return node.getNamespaceURI(); } // // This is a temporary hack!! // protected String getFallbackNamepaceURI(CMElementDeclaration ed) { String fallbackNamepaceURI = null; CMDocument cmDocument = (CMDocument)ed.getProperty("CMDocument"); //$NON-NLS-1$ if (cmDocument != null) { fallbackNamepaceURI = (String)cmDocument.getProperty("http://org.eclipse.wst/cm/properties/targetNamespaceURI"); //$NON-NLS-1$ } return fallbackNamepaceURI; } /** * Encode the Element's NodeList as a List of strings that the validator recognizes */ public List createContentSpecificationList(Element element, CMElementDeclaration ed) { boolean isNamespaceAware = isNamespaceAware(ed); Vector v = new Vector(); for (Node childNode = element.getFirstChild(); childNode != null; childNode = childNode.getNextSibling()) { v.add(createContentSpecification(childNode, isNamespaceAware, isNamespaceAware ? getFallbackNamepaceURI(ed) : null)); } return v; } public List createContentSpecificationList(List nodeList, CMElementDeclaration ed) { boolean isNamespaceAware = isNamespaceAware(ed); Vector v = new Vector(); for (Iterator i = nodeList.iterator(); i.hasNext(); ) { Node node = (Node)i.next(); v.add(createContentSpecification(node, isNamespaceAware, getFallbackNamepaceURI(ed))); } return v; } /** * Encode the Node as a string that the validator recognizes */ public String createContentSpecification(Node node, boolean isNamespaceAware, String fallbackNamepaceURI) { String result = "!"; //$NON-NLS-1$ switch (node.getNodeType()) { case Node.ELEMENT_NODE : { String nodeName = node.getNodeName(); if (nodeName.startsWith("jsp:")) //$NON-NLS-1$ { result = "!"; // treat it as a comment so that it's ignored by the validator //$NON-NLS-1$ } else { if (isNamespaceAware) { result = DOMNamespaceHelper.getUnprefixedName(nodeName); String uri = getNamespaceURI(node); if (uri != null) { result = "[" + uri + "]" + result; //$NON-NLS-1$ //$NON-NLS-2$ } else if (fallbackNamepaceURI != null) { result = "[" + fallbackNamepaceURI + "]" + result; //$NON-NLS-1$ //$NON-NLS-2$ } } else { result = nodeName; } } //ContentModelManager.println("result " + result); break; } case Node.PROCESSING_INSTRUCTION_NODE : { result = "?"; //$NON-NLS-1$ break; } case Node.COMMENT_NODE : { result = "!"; //$NON-NLS-1$ break; } case Node.CDATA_SECTION_NODE : { result = "\"" + node.getNodeName() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ break; } case Node.TEXT_NODE : { String data = ((Text)node).getData(); // here we test to see if the test node is 'ignorable' if (data != null && data.trim().length() > 0) { result = "\"" + node.getNodeName() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ } else { result = "!"; // todo... use another symbol? //$NON-NLS-1$ } break; } } return result; } /** * */ public List createContentSpecificationList(CMNode cmNode) { List list = new Vector(); switch (cmNode.getNodeType()) { case CMNode.ELEMENT_DECLARATION : { list.add(createContentSpecificationForCMElementDeclaration((CMElementDeclaration)cmNode)); break; } case CMNode.DATA_TYPE : { list.add("\"" + cmNode.getNodeName() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ break; } case CMNode.GROUP : { createContentSpecificationListForCMGroup((CMGroup)cmNode, list); break; } case CMNode.ANY_ELEMENT : { list.add("*"); //$NON-NLS-1$ break; } default : { list.add("!"); //$NON-NLS-1$ } } return list; } /** * */ protected String createContentSpecificationForCMElementDeclaration(CMElementDeclaration ed) { CMDocument document = (CMDocument)ed.getProperty("CMDocument"); //$NON-NLS-1$ String uri = document != null ? (String)document.getProperty("http://org.eclipse.wst/cm/properties/targetNamespaceURI") : null; //$NON-NLS-1$ String string = ed.getNodeName(); if (uri != null) { string = "[" + uri + "]" + string; //$NON-NLS-1$ //$NON-NLS-2$ } return string; } /** * */ protected void createContentSpecificationListForCMGroup(CMGroup group, List list) { CMGroupContentVisitor visitor = new CMGroupContentVisitor(group, list); visitor.visitCMNode(group); } protected class CMGroupContentVisitor extends CMVisitor { protected CMGroup root; protected List list; public CMGroupContentVisitor(CMGroup root, List list) { this.root = root; this.list = list; } public void visitCMElementDeclaration(CMElementDeclaration ed) { if (ed.getMinOccur() > 0) { list.add(createContentSpecificationForCMElementDeclaration(ed)); } } public void visitCMAnyElement(CMAnyElement anyElement) { list.add("*"); //$NON-NLS-1$ } public void visitCMGroup(CMGroup group) { if (group == root || group.getMinOccur() > 0) { int op = group.getOperator(); if (op == CMGroup.SEQUENCE) { super.visitCMGroup(group); } else if (op == CMGroup.CHOICE) { CMNodeList nodeList = group.getChildNodes(); if (nodeList.getLength() > 0) { visitCMNode(nodeList.item(0)); } } } } } public boolean isNamespaceAware(CMElementDeclaration ed) { return ed != null ? ed.getProperty("http://org.eclipse.wst/cm/properties/isNameSpaceAware") != null : false; //$NON-NLS-1$ } /** * */ public CMNode[] getOriginArray(CMElementDeclaration ed, Element element) { ElementPathRecordingResult result = new ElementPathRecordingResult(); getOriginArray(ed, createContentSpecificationList(element, ed), stringContentComparitor, result); return result.getOriginArray(); } /** * */ public MatchModelNode getMatchModel(CMElementDeclaration ed, Element element) { MatchModelNode matchModelNode = null; PathRecordingResult result = new PathRecordingResult(); validate(ed, createContentSpecificationList(element, ed), stringContentComparitor, result); if (result.isValid) { matchModelNode = result.getMatchModel(); } return matchModelNode; } public List clone(List list) { List result = new Vector(list.size()); result.addAll(list); return result; } /** * */ public boolean canInsert(CMElementDeclaration ed, List contentSpecificationList, int insertIndex, CMNode cmNode) { List clonedList = clone(contentSpecificationList); insert(clonedList, insertIndex, cmNode); boolean result = isPartiallyValid(ed, clonedList); return result; } /** * */ public boolean canInsert(CMElementDeclaration ed, List contentSpecificationList, int insertIndex, List cmNodeList) { List clonedList = clone(contentSpecificationList); insert(clonedList, insertIndex, cmNodeList); return isValid(ed, clonedList); } /** * */ public boolean canRemove(CMElementDeclaration ed, List contentSpecificationList, int startRemoveIndex) { return canRemove(ed, contentSpecificationList, startRemoveIndex, startRemoveIndex); } /** * */ public boolean canRemove(CMElementDeclaration ed, List contentSpecificationList, int startRemoveIndex, int endRemoveIndex) { List clonedList = clone(contentSpecificationList); remove(clonedList, startRemoveIndex, endRemoveIndex); return isValid(ed, clonedList); } /** * */ public boolean canReplace(CMElementDeclaration ed, List contentSpecificationList, int startRemoveIndex, int endRemoveIndex, CMNode cmNode) { List clonedList = clone(contentSpecificationList); remove(clonedList, startRemoveIndex, endRemoveIndex); insert(clonedList, startRemoveIndex, cmNode); return isValid(ed, clonedList); } /** * */ public boolean isValid(CMElementDeclaration ed, List contentSpecificationList) { Result result = new Result(); validate(ed, contentSpecificationList, stringContentComparitor, result); return result.isValid; } public boolean isPartiallyValid(CMElementDeclaration ed, List contentSpecificationList) { CMValidator.ElementPathRecordingResult result = new CMValidator.ElementPathRecordingResult(); validate(ed, contentSpecificationList, stringContentComparitor, result); int count = getElementCount(contentSpecificationList); //System.out.println("elementOriginList " + result.getPartialValidationCount() + "vs" + count); return result.getPartialValidationCount() >= count; } public int getElementCount(List contentSpecificationList) { int count = 0; for (Iterator i = contentSpecificationList.iterator(); i.hasNext(); ) { if (stringContentComparitor.isElement(i.next())) { count++; } } return count; } protected Result validate(CMElementDeclaration ed, Element element) { Result result = new Result(); validate(ed, createContentSpecificationList(element, ed), stringContentComparitor, result); return result; } protected void remove(List stringList, int startRemoveIndex, int endRemoveIndex) { if (startRemoveIndex != -1) { for (int i = startRemoveIndex; i <= endRemoveIndex; i++) { stringList.remove(i); } } } protected void insert(List stringList, int insertIndex, CMNode cmNode) { if (insertIndex != -1) { stringList.addAll(insertIndex, createContentSpecificationList(cmNode)); } } protected void insert(List stringList, int insertIndex, List cmNodeList) { if (insertIndex != -1) { int insertListSize = cmNodeList.size(); for (int i = insertListSize - 1; i >= 0; i--) { CMNode cmNode = (CMNode)cmNodeList.get(i); stringList.addAll(insertIndex, createContentSpecificationList(cmNode)); } } } }