blob: 4a11a27922ce1da433460ea6d384c392cdec3fa7 [file] [log] [blame]
/*******************************************************************************
* 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));
}
}
}
}