Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl')
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/BaseAssociationProvider.java88
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentLoader.java214
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentManagerImpl.java321
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentReferenceImpl.java42
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/InferredGrammarBuildingCMDocumentLoader.java189
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryActionHelper.java570
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryImpl.java848
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/SimpleAssociationProvider.java49
-rw-r--r--bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/XMLAssociationProvider.java402
9 files changed, 2723 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/BaseAssociationProvider.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/BaseAssociationProvider.java
new file mode 100644
index 0000000000..aac4555212
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/BaseAssociationProvider.java
@@ -0,0 +1,88 @@
+/*
+* Copyright (c) 2002 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Common Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/cpl-v10.html
+*
+* Contributors:
+* IBM - Initial API and implementation
+* Jens Lukowski/Innoopract - initial renaming/restructuring
+*
+*/
+package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl;
+
+import org.eclipse.wst.sse.core.internal.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMDataType;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMNode;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQueryAssociationProvider;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+
+/**
+ *
+ */
+public abstract class BaseAssociationProvider implements ModelQueryAssociationProvider
+{
+ public BaseAssociationProvider()
+ {
+ }
+
+ public CMNode getCMNode(Node node)
+ {
+ CMNode result = null;
+ switch (node.getNodeType())
+ {
+ case Node.ATTRIBUTE_NODE :
+ {
+ result = getCMAttributeDeclaration((Attr)node);
+ break;
+ }
+ case Node.ELEMENT_NODE :
+ {
+ result = getCMElementDeclaration((Element)node);
+ break;
+ }
+ case Node.CDATA_SECTION_NODE :
+ case Node.TEXT_NODE :
+ {
+ result = getCMDataType((Text)node);
+ break;
+ }
+ }
+ return result;
+ }
+
+
+ public CMDataType getCMDataType(Text text)
+ {
+ CMDataType result = null;
+ Node parentNode = text.getParentNode();
+ if (parentNode != null && parentNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ CMElementDeclaration ed = getCMElementDeclaration((Element)parentNode);
+ result = ed.getDataType();
+ }
+ return result;
+ }
+
+
+ public CMAttributeDeclaration getCMAttributeDeclaration(Attr attr)
+ {
+ CMAttributeDeclaration result = null;
+ Element element = attr.getOwnerElement();
+ if (element != null)
+ {
+ CMElementDeclaration ed = getCMElementDeclaration(element);
+ if (ed != null)
+ {
+ result = (CMAttributeDeclaration)ed.getAttributes().getNamedItem(attr.getName());
+ }
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentLoader.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentLoader.java
new file mode 100644
index 0000000000..99e1c0e432
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentLoader.java
@@ -0,0 +1,214 @@
+/*
+* Copyright (c) 2002 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Common Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/cpl-v10.html
+*
+* Contributors:
+* IBM - Initial API and implementation
+* Jens Lukowski/Innoopract - initial renaming/restructuring
+*
+*/
+package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQuery;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.CMDocumentCache;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceInfo;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceTable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+
+/**
+ *
+ */
+public class CMDocumentLoader
+{
+ protected Document document;
+ protected ModelQuery modelQuery;
+ protected CMDocumentManager cmDocumentManager;
+ protected boolean isInferredGrammarEnabled = true;
+ protected CMDocumentLoadingNamespaceTable namespaceTable;
+ protected int count = 0;
+
+ public CMDocumentLoader(Document document, ModelQuery modelQuery)
+ {
+ this(document, modelQuery.getCMDocumentManager());
+ }
+
+ public CMDocumentLoader(Document document, CMDocumentManager cmDocumentManager)
+ {
+ this.document = document;
+ this.cmDocumentManager = cmDocumentManager;
+ }
+
+ public void loadCMDocuments()
+ {
+ //System.out.println("----------loadCMDocuments ------------");
+ long time = System.currentTimeMillis();
+
+ boolean walkDocument = false;
+
+ cmDocumentManager.removeAllReferences();
+
+ String[] doctypeInfo = XMLAssociationProvider.getDoctypeInfo(document);
+ if (doctypeInfo != null)
+ {
+ // load the doctype if required
+ walkDocument = handleGrammar(doctypeInfo[0], doctypeInfo[1], "DTD");
+ }
+ else
+ {
+ Element element = getRootElement(document);
+ if (element != null)
+ {
+ namespaceTable = new CMDocumentLoadingNamespaceTable(document);
+ namespaceTable.addElement(element);
+ if (namespaceTable.isNamespaceEncountered())
+ {
+ walkDocument = true;
+ //System.out.println("isNamespaceAware");
+ }
+ else
+ {
+ namespaceTable = null;
+ walkDocument = isInferredGrammarEnabled;
+ //System.out.println("is NOT namespaceAware");
+ }
+ }
+ }
+
+ if (walkDocument)
+ {
+ visitNode(document);
+ }
+
+ //System.out.println("--- elapsed time (" + count + ") = " + (System.currentTimeMillis() - time));
+ }
+
+
+ public boolean handleGrammar(String publicId, String systemId, String type)
+ {
+ boolean result = false;
+
+ int status = cmDocumentManager.getCMDocumentStatus(publicId);
+ if (status == CMDocumentCache.STATUS_NOT_LOADED)
+ {
+ cmDocumentManager.addCMDocumentReference(publicId, systemId, type);
+ }
+ else if (status == CMDocumentCache.STATUS_ERROR)
+ {
+ result = true;
+ }
+ return result;
+ }
+
+
+ public void handleElement(Element element)
+ {
+ visitChildNodes(element);
+ }
+
+
+ public void handleElementNS(Element element)
+ {
+ namespaceTable.addElement(element);
+ visitChildNodes(element);
+ }
+
+
+ public void visitNode(Node node)
+ {
+ int nodeType = node.getNodeType();
+ if (nodeType == Node.ELEMENT_NODE)
+ {
+ count++;
+
+ Element element = (Element)node;
+ if (namespaceTable == null)
+ {
+ handleElement(element);
+ }
+ else
+ {
+ handleElementNS(element);
+ }
+ }
+ else if (nodeType == Node.DOCUMENT_NODE)
+ {
+ visitChildNodes(node);
+ }
+ }
+
+
+ protected void visitChildNodes(Node node)
+ {
+ for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling())
+ {
+ visitNode(child);
+ }
+ }
+
+
+ protected class CMDocumentLoadingNamespaceTable extends NamespaceTable
+ {
+ protected List newNamespaceList;
+
+ public CMDocumentLoadingNamespaceTable(Document document)
+ {
+ super(document);
+ }
+
+
+ public void addElement(Element element)
+ {
+ newNamespaceList = null;
+ super.addElement(element);
+ if (newNamespaceList != null)
+ {
+ for (Iterator i = newNamespaceList.iterator(); i.hasNext(); )
+ {
+ NamespaceInfo info = (NamespaceInfo)i.next();
+ handleGrammar(info.uri, info.locationHint, "XSD");
+ }
+ }
+ }
+
+
+ protected void internalAddNamespaceInfo(String key, NamespaceInfo info)
+ {
+ super.internalAddNamespaceInfo(key, info);
+ if (newNamespaceList == null)
+ {
+ newNamespaceList = new ArrayList();
+ }
+ newNamespaceList.add(info);
+ }
+ }
+
+
+ protected Element getRootElement(Document document)
+ {
+ Element result = null;
+ NodeList nodeList = document.getChildNodes();
+ int nodeListLength = nodeList.getLength();
+ for (int i = 0 ; i < nodeListLength; i++)
+ {
+ Node node = nodeList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ result = (Element)node;
+ break;
+ }
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentManagerImpl.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentManagerImpl.java
new file mode 100644
index 0000000000..30dc411a30
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentManagerImpl.java
@@ -0,0 +1,321 @@
+/*
+* Copyright (c) 2002 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Common Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/cpl-v10.html
+*
+* Contributors:
+* IBM - Initial API and implementation
+* Jens Lukowski/Innoopract - initial renaming/restructuring
+*
+*/
+package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument;
+import org.eclipse.wst.sse.core.internal.contentmodel.ContentModelManager;
+import org.eclipse.wst.sse.core.internal.contentmodel.internal.annotation.AnnotationUtility;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManagerListener;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentReferenceProvider;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.CMDocumentCache;
+
+
+/**
+ *
+ */
+public class CMDocumentManagerImpl implements CMDocumentManager
+{
+ protected CMDocumentCache cmDocumentCache;
+ protected CMDocumentReferenceProvider cmDocumentReferenceProvider;
+ protected List listenerList = new Vector();
+ protected Hashtable propertyTable = new Hashtable();
+ protected Hashtable publicIdTable = new Hashtable();
+
+
+ public CMDocumentManagerImpl(CMDocumentCache cmDocumentCache, CMDocumentReferenceProvider cmDocumentReferenceProvider)
+ {
+ this.cmDocumentCache = cmDocumentCache;
+ this.cmDocumentReferenceProvider = cmDocumentReferenceProvider;
+ setPropertyEnabled(PROPERTY_AUTO_LOAD, true);
+ setPropertyEnabled(PROPERTY_USE_CACHED_RESOLVED_URI, false);
+ }
+
+
+ public CMDocumentCache getCMDocumentCache()
+ {
+ return cmDocumentCache;
+ }
+
+
+ public void setPropertyEnabled(String propertyName, boolean value)
+ {
+ propertyTable.put(propertyName, value ? "true" : "false");
+ for (Iterator i = listenerList.iterator(); i.hasNext(); )
+ {
+ CMDocumentManagerListener listener = (CMDocumentManagerListener)i.next();
+ listener.propertyChanged(this, propertyName);
+ }
+ }
+
+
+ public boolean getPropertyEnabled(String propertyName)
+ {
+ Object object = propertyTable.get(propertyName);
+ return object != null && object.equals("true");
+ }
+
+
+ public void addListener(CMDocumentManagerListener listener)
+ {
+ listenerList.add(listener);
+ cmDocumentCache.addListener(listener);
+ }
+
+
+ public void removeListener(CMDocumentManagerListener listener)
+ {
+ listenerList.remove(listener);
+ cmDocumentCache.removeListener(listener);
+ }
+
+
+ protected String lookupResolvedURI(String publicId)
+ {
+ String key = publicId != null ? publicId : "";
+ return (String)publicIdTable.get(key);
+ }
+
+
+ protected String lookupOrCreateResolvedURI(String publicId, String systemId)
+ {
+ String resolvedURI = null;
+
+ String key = publicId != null ? publicId : "";
+
+ if (getPropertyEnabled(PROPERTY_USE_CACHED_RESOLVED_URI))
+ {
+ resolvedURI = (String)publicIdTable.get(key);
+ }
+
+ if (resolvedURI == null)
+ {
+ resolvedURI = cmDocumentReferenceProvider.resolveGrammarURI(publicId, systemId);
+ if (resolvedURI == null)
+ {
+ resolvedURI = "";
+ }
+ publicIdTable.put(key, resolvedURI);
+ }
+
+ return resolvedURI;
+ }
+
+
+ public int getCMDocumentStatus(String publicId)
+ {
+ int status = CMDocumentCache.STATUS_NOT_LOADED;
+ String resolvedURI = lookupResolvedURI(publicId);
+ if (resolvedURI != null)
+ {
+ status = cmDocumentCache.getStatus(resolvedURI);
+ }
+ return status;
+ }
+
+
+ public CMDocument getCMDocument(String publicId)
+ {
+ CMDocument result = null;
+ String resolvedURI = lookupResolvedURI(publicId);
+ if (resolvedURI != null)
+ {
+ result = cmDocumentCache.getCMDocument(resolvedURI);
+ }
+ return result;
+ }
+
+
+ public CMDocument getCMDocument(String publicId, String systemId, String type)
+ {
+ CMDocument cmDocument = null;
+ String resolvedURI = null;
+
+ if (getPropertyEnabled(PROPERTY_AUTO_LOAD))
+ {
+ resolvedURI = lookupOrCreateResolvedURI(publicId, systemId);
+ }
+ else
+ {
+ resolvedURI = lookupResolvedURI(publicId);
+ }
+
+ if (resolvedURI != null)
+ {
+ int status = cmDocumentCache.getStatus(resolvedURI);
+ if (status == CMDocumentCache.STATUS_LOADED)
+ {
+ cmDocument = cmDocumentCache.getCMDocument(resolvedURI);
+ }
+ else if (status == CMDocumentCache.STATUS_NOT_LOADED)
+ {
+ if (getPropertyEnabled(PROPERTY_AUTO_LOAD))
+ {
+ cmDocument = loadCMDocument(publicId, resolvedURI, type, getPropertyEnabled(PROPERTY_ASYNC_LOAD));
+ }
+ }
+ }
+ return cmDocument;
+ }
+
+ /**
+ * @deprecated
+ */
+ public CMDocument getCMDocument(String publicId, String resolvedURI)
+ {
+ CMDocument cmDocument = null;
+
+ if (resolvedURI != null)
+ {
+ int status = cmDocumentCache.getStatus(resolvedURI);
+ if (status == CMDocumentCache.STATUS_LOADED)
+ {
+ cmDocument = cmDocumentCache.getCMDocument(resolvedURI);
+ }
+ else if (status == CMDocumentCache.STATUS_NOT_LOADED)
+ {
+ if (getPropertyEnabled(PROPERTY_AUTO_LOAD))
+ {
+ cmDocument = loadCMDocument(publicId, resolvedURI, "", getPropertyEnabled(PROPERTY_ASYNC_LOAD));
+ }
+ }
+ }
+ return cmDocument;
+ }
+
+ public void addCMDocumentReference(String publicId, String systemId, String type)
+ {
+ String resolvedURI = lookupOrCreateResolvedURI(publicId, systemId);
+ if (resolvedURI != null && resolvedURI.length() > 0)
+ {
+ int status = cmDocumentCache.getStatus(resolvedURI);
+ if (status == CMDocumentCache.STATUS_NOT_LOADED)
+ {
+ loadCMDocument(publicId, resolvedURI, type, getPropertyEnabled(PROPERTY_ASYNC_LOAD));
+ }
+ }
+ }
+
+
+ public void addCMDocument(String publicId, String systemId, String resolvedURI, String type, CMDocument cmDocument)
+ {
+ String key = publicId != null ? publicId : "";
+ publicIdTable.put(key, resolvedURI);
+ cmDocumentCache.putCMDocument(resolvedURI, cmDocument);
+ }
+
+
+ protected CMDocument loadCMDocument(final String publicId, final String resolvedURI, final String type, boolean async)
+ {
+ CMDocument result = null;
+
+ //System.out.println("about to build CMDocument(" + publicId + ", " + unresolvedURI + " = " + resolvedURI + ")");
+ if (async)
+ {
+ cmDocumentCache.setStatus(resolvedURI, CMDocumentCache.STATUS_LOADING);
+ //Thread thread = new Thread(new AsyncBuildOperation(publicId, resolvedURI, type));
+ //thread.start();
+ Job job = new Job("loading " + resolvedURI)
+ {
+ public boolean belongsTo(Object family)
+ {
+ boolean result = (family == CMDocumentManager.class);
+ return result;
+ }
+
+ protected IStatus run(IProgressMonitor monitor)
+ {
+ try
+ {
+ new AsyncBuildOperation(publicId, resolvedURI, type).run();
+ }
+ catch (Exception e)
+ {
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.schedule();
+ }
+ else
+ {
+ result = buildCMDocument(publicId, resolvedURI, type);
+ }
+ return result;
+ }
+
+
+
+ protected class AsyncBuildOperation implements Runnable
+ {
+ protected String publicId;
+ protected String resolvedURI;
+ protected String type;
+
+ public AsyncBuildOperation(String publicId, String resolvedURI, String type)
+ {
+ this.publicId = publicId;
+ this.resolvedURI = resolvedURI;
+ this.type = type;
+ }
+
+ public void run()
+ {
+ buildCMDocument(publicId, resolvedURI, type);
+ }
+ }
+
+
+ public synchronized CMDocument buildCMDocument(String publicId, String resolvedURI, String type)
+ {
+ cmDocumentCache.setStatus(resolvedURI, CMDocumentCache.STATUS_LOADING);
+
+ CMDocument result = null;
+ int x = 1;
+ x++;
+ if (resolvedURI != null && resolvedURI.length() > 0)
+ {
+ // TODO... pass the TYPE thru to the CMDocumentBuilder
+ result = ContentModelManager.getInstance().createCMDocument(resolvedURI, type);
+ }
+ if (result != null)
+ {
+ // load the annotation files for the document
+ if (publicId != null)
+ {
+ AnnotationUtility.loadAnnotationsForGrammar(publicId, result);
+ }
+ cmDocumentCache.putCMDocument(resolvedURI, result);
+ }
+ else
+ {
+ cmDocumentCache.setStatus(resolvedURI, CMDocumentCache.STATUS_ERROR);
+ }
+ return result;
+ }
+
+ public void removeAllReferences()
+ {
+ // TODO... initiate a timed release of the entries in the CMDocumentCache
+ publicIdTable = new Hashtable();
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentReferenceImpl.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentReferenceImpl.java
new file mode 100644
index 0000000000..52be1bede2
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentReferenceImpl.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2002 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Common Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/cpl-v10.html
+*
+* Contributors:
+* IBM - Initial API and implementation
+* Jens Lukowski/Innoopract - initial renaming/restructuring
+*
+*/
+package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl;
+
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentReference;
+
+public class CMDocumentReferenceImpl implements CMDocumentReference
+{
+ protected String systemId;
+ protected String publicId;
+
+ public CMDocumentReferenceImpl(String publicId, String systemId)
+ {
+ this.publicId = publicId;
+ this.systemId = systemId;
+ }
+
+ public String getPublicId()
+ {
+ return publicId;
+ }
+
+ public String getSystemId()
+ {
+ return systemId;
+ }
+
+ public String toString()
+ {
+ return "[" + publicId + ", " + systemId + "]";
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/InferredGrammarBuildingCMDocumentLoader.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/InferredGrammarBuildingCMDocumentLoader.java
new file mode 100644
index 0000000000..18200c8719
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/InferredGrammarBuildingCMDocumentLoader.java
@@ -0,0 +1,189 @@
+/*
+* Copyright (c) 2002 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Common Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/cpl-v10.html
+*
+* Contributors:
+* IBM - Initial API and implementation
+* Jens Lukowski/Innoopract - initial renaming/restructuring
+*
+*/
+package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl;
+
+import java.util.Hashtable;
+
+import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.internal.modelqueryimpl.InferredGrammarFactory;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQuery;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.CMDocumentCache;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+
+/**
+ *
+ */
+public class InferredGrammarBuildingCMDocumentLoader extends CMDocumentLoader
+{
+ protected CMElementDeclaration inferredCMElementDeclaration;
+ protected CMDocument inferredCMDocument;
+ protected InferredGrammarFactory inferredGrammarFactory;
+ protected Hashtable createdCMDocumentTable;
+
+ public InferredGrammarBuildingCMDocumentLoader(Document document, ModelQuery modelQuery)
+ {
+ this(document, modelQuery.getCMDocumentManager());
+ }
+
+ public InferredGrammarBuildingCMDocumentLoader(Document document, CMDocumentManager cmDocumentManager)
+ {
+ super(document, cmDocumentManager);
+ createdCMDocumentTable = new Hashtable();
+ inferredGrammarFactory = new InferredGrammarFactory();
+ }
+
+
+ public void loadCMDocuments()
+ {
+ //System.out.println("----------loadCMDocuments ------------");
+ if (inferredGrammarFactory != null)
+ {
+ long time = System.currentTimeMillis();
+ super.loadCMDocuments();
+ //System.out.println("--- elapsed time (" + count + ") = " + (System.currentTimeMillis() - time));
+ //inferredGrammarFactory.debugPrint(createdCMDocumentTable.values());
+ }
+
+ }
+
+ public void handleElement(Element element)
+ {
+ CMElementDeclaration parentInferredCMElementDeclaration = inferredCMElementDeclaration;
+
+ if (inferredCMDocument == null)
+ {
+ String cacheKey = "inferred-document";
+ inferredCMDocument = inferredGrammarFactory.createCMDocument("");
+ cmDocumentManager.addCMDocument("", "", cacheKey, "DTD", inferredCMDocument);
+ createdCMDocumentTable.put(cacheKey, inferredCMDocument);
+ }
+
+ inferredCMElementDeclaration = inferredGrammarFactory.createCMElementDeclaration(inferredCMDocument, element, false);
+
+ if (parentInferredCMElementDeclaration != null)
+ {
+ inferredGrammarFactory.createCMContent(inferredCMDocument, parentInferredCMElementDeclaration, inferredCMDocument, inferredCMElementDeclaration, false, null);
+ }
+
+
+ visitChildNodes(element);
+
+ // reset the 'current' state to inital values
+ inferredCMElementDeclaration = parentInferredCMElementDeclaration;
+ }
+
+
+ public void handleElementNS(Element element)
+ {
+ CMDocument parentInferredCMDocument = inferredCMDocument;
+ CMElementDeclaration parentInferredCMElementDeclaration = inferredCMElementDeclaration;
+
+ inferredCMDocument = null;
+ inferredCMElementDeclaration = null;
+
+ // by adding the element to the namespaceTable, handleGrammar() will get called for any schema references
+ if (element.getParentNode() != document)
+ {
+ namespaceTable.addElement(element);
+ }
+
+ String prefix = element.getPrefix();
+ String uri = namespaceTable.getURIForPrefix(prefix);
+
+ if (uri == null && element.getParentNode() == document)
+ {
+ // when this is the root element
+ // we need to add an implied "no namespace schema location"
+ uri = "ommitted-namespace";
+ namespaceTable.addNamespaceInfo(prefix, uri, "");
+ }
+
+ // here's where we update the inferred grammar if required
+ //
+ boolean createCMElementDeclaration = true;
+
+ boolean isLocal = (uri == null && prefix == null);
+ if (isLocal)
+ {
+ if (parentInferredCMDocument == null)
+ {
+ // this is a local element... and the parent is not inferred (e.g) it has a known grammar
+ // so we don't need to create an element declaration for this element
+ createCMElementDeclaration = false;
+ }
+ else
+ {
+ if (uri == null)
+ {
+ uri = "ommitted-namespace";
+ }
+ }
+ }
+
+ if (createCMElementDeclaration)
+ {
+ if (isLocal)
+ {
+ inferredCMDocument = parentInferredCMDocument;
+ inferredCMElementDeclaration = inferredGrammarFactory.createCMElementDeclaration(inferredCMDocument, element, true);
+ }
+ else
+ {
+ boolean createCMDocument = false;
+
+ String cacheKey = "inferred-document" + uri;
+ inferredCMDocument = (CMDocument)createdCMDocumentTable.get(cacheKey);
+
+ if (inferredCMDocument == null)
+ {
+ // we don't have an inferred document for this uri yet... let's see of we need one
+ int status = cmDocumentManager.getCMDocumentStatus(uri);
+ if (status == CMDocumentCache.STATUS_NOT_LOADED || status == CMDocumentCache.STATUS_ERROR)
+ {
+ // the cache does not contain a 'proper' CMDocument for this uri
+ // so we need to create an inferred one
+ createCMDocument = true;
+ }
+ }
+
+ if (createCMDocument)
+ {
+ //System.out.println("encountered element {" + element.getNodeName() + "} ... creating inferred CMDocument for " + uri);
+ inferredCMDocument = inferredGrammarFactory.createCMDocument(uri);
+ cmDocumentManager.addCMDocument(uri, "", cacheKey, "XSD", inferredCMDocument);
+ createdCMDocumentTable.put(cacheKey, inferredCMDocument);
+ }
+
+ if (inferredCMDocument != null)
+ {
+ inferredCMElementDeclaration = inferredGrammarFactory.createCMElementDeclaration(inferredCMDocument, element, false);
+ }
+ }
+
+ if (parentInferredCMElementDeclaration != null)
+ {
+ inferredGrammarFactory.createCMContent(parentInferredCMDocument, parentInferredCMElementDeclaration, inferredCMDocument, inferredCMElementDeclaration, isLocal, uri);
+ }
+ }
+
+ visitChildNodes(element);
+
+ // reset the 'current' state to inital values
+ inferredCMElementDeclaration = parentInferredCMElementDeclaration;
+ inferredCMDocument = parentInferredCMDocument;
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryActionHelper.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryActionHelper.java
new file mode 100644
index 0000000000..2f687a81de
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryActionHelper.java
@@ -0,0 +1,570 @@
+/*
+* Copyright (c) 2002 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Common Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/cpl-v10.html
+*
+* Contributors:
+* IBM - Initial API and implementation
+* Jens Lukowski/Innoopract - initial renaming/restructuring
+*
+*/
+package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.eclipse.wst.sse.core.internal.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMGroup;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMNamedNodeMap;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMNode;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMNodeList;
+import org.eclipse.wst.sse.core.internal.contentmodel.internal.util.CMValidator;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQuery;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQueryAction;
+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 ModelQueryActionHelper
+{
+ protected ModelQueryImpl modelQuery;
+
+ protected static class Action implements ModelQueryAction
+ {
+ public int kind;
+ public int startIndex;
+ public int endIndex;
+ public Node parent;
+ public CMNode cmNode;
+ public Object userData;
+
+ public Action(int kind, Node parent, CMNode cmNode)
+ {
+ this.kind = kind;
+ this.parent = parent;
+ this.cmNode = cmNode;
+ }
+
+ public Action(int kind, Node parent, CMNode cmNode, int startIndex, int endIndex)
+ {
+ this.kind = kind;
+ this.parent = parent;
+ this.cmNode = cmNode;
+ this.startIndex = startIndex;
+ this.endIndex = endIndex;
+ }
+
+ public int getKind()
+ {
+ return kind;
+ }
+
+ public int getStartIndex()
+ {
+ return startIndex;
+ }
+
+ public int getEndIndex()
+ {
+ return endIndex;
+ }
+
+ public Node getParent()
+ {
+ return parent;
+ }
+
+ public CMNode getCMNode()
+ {
+ return cmNode;
+ }
+
+ public Object getUserData()
+ {
+ return userData;
+ }
+
+ public void setUserData(Object object)
+ {
+ userData = object;
+ }
+
+ public void performAction()
+ {
+ }
+ }
+
+
+ public ModelQueryActionHelper(ModelQueryImpl modelQuery)
+ {
+ this.modelQuery = modelQuery;
+ }
+
+
+ public void getAllActions(Element parent, CMElementDeclaration ed, int validityChecking, List actionList)
+ {
+ }
+
+
+ // insert actions
+ //
+ public void getInsertActions(Element parent, CMElementDeclaration ed, int index, int includeOptions, int validityChecking, List actionList)
+ {
+ if ((includeOptions & ModelQuery.INCLUDE_ATTRIBUTES) != 0)
+ {
+ getInsertAttributeActions(parent, ed, validityChecking, actionList);
+ }
+ includeOptions &= ~ModelQuery.INCLUDE_ATTRIBUTES;
+ if ((includeOptions & ModelQuery.INCLUDE_CHILD_NODES) != 0)
+ {
+ if (index != -1)
+ {
+ getInsertChildNodeActionsAtIndex(parent, ed, index, includeOptions, validityChecking, actionList);
+ }
+ else
+ {
+ getInsertChildNodeActions(parent, ed, includeOptions, validityChecking, actionList);
+ }
+ }
+ }
+
+
+
+ protected void getInsertAttributeActions(Element parent, CMElementDeclaration ed, int validityChecking, List actionList)
+ {
+ // get actions for each insertable attribute
+ //
+ List availableAttributeList = modelQuery.getAvailableContent(parent, ed, ModelQuery.INCLUDE_ATTRIBUTES);
+
+ for (Iterator i = availableAttributeList.iterator(); i.hasNext(); )
+ {
+ CMAttributeDeclaration ad = (CMAttributeDeclaration)i.next();
+ if (modelQuery.canInsert(parent, ed, ad, 0, validityChecking))
+ {
+ Action action = new Action(ModelQueryAction.INSERT, parent, ad);
+ actionList.add(action);
+ }
+ }
+ }
+
+
+ protected void getInsertChildNodeActionsAtIndex(Element parent, CMElementDeclaration ed, int index, int includeOptions, int validityChecking, List actionList)
+ {
+ // get actions for each insertable attribute
+ //
+ int size = parent.getChildNodes().getLength();
+ if (index <= size)
+ {
+ List contentSpecificationList = modelQuery.getValidator().createContentSpecificationList(parent, ed);
+ List availableChildNodeList = modelQuery.getAvailableContent(parent, ed, includeOptions);
+
+ boolean isSimpleChoice = isSimpleChoiceGroupContentModel(ed);
+
+ for (Iterator i = availableChildNodeList.iterator(); i.hasNext(); )
+ {
+ CMNode cmNode = (CMNode)i.next();
+ if (isSimpleChoice || modelQuery.canInsert(parent, ed, cmNode, index, validityChecking, contentSpecificationList))
+ {
+ Action action = new Action(ModelQueryAction.INSERT, parent, cmNode, index, index);
+ actionList.add(action);
+ }
+ }
+ }
+ }
+
+
+ protected boolean isSimpleChoiceGroupContentModel(CMElementDeclaration ed)
+ {
+ boolean result = false;
+ CMNode cmNode = ed.getContent();
+ if (cmNode != null && cmNode.getNodeType() == CMNode.GROUP)
+ {
+ CMGroup cmGroup = (CMGroup)cmNode;
+ if (cmGroup.getOperator() == CMGroup.CHOICE && cmGroup.getMaxOccur() == -1)
+ {
+ result = true;
+ CMNodeList list = cmGroup.getChildNodes();
+ for (int i = list.getLength() - 1; i >= 0; i--)
+ {
+ if (list.item(i).getNodeType() != CMNode.ELEMENT_DECLARATION)
+ {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+
+ protected void getInsertChildNodeActions(Element parent, CMElementDeclaration ed, int includeOptions, int validityChecking, List actionList)
+ {
+ int size = parent.getChildNodes().getLength();
+ List contentSpecificationList = modelQuery.getValidator().createContentSpecificationList(parent, ed);
+ List availableChildNodeList = modelQuery.getAvailableContent(parent, ed, includeOptions);
+
+ boolean isSimpleChoice = isSimpleChoiceGroupContentModel(ed);
+
+ for (Iterator iterator = availableChildNodeList.iterator(); iterator.hasNext(); )
+ {
+ CMNode cmNode = (CMNode)iterator.next();
+ for (int i = size; i >= 0; i--)
+ {
+ if (isSimpleChoice || modelQuery.canInsert(parent, ed, cmNode, i, validityChecking, contentSpecificationList))
+ {
+ Action action = new Action(ModelQueryAction.INSERT, parent, cmNode, i, i);
+ actionList.add(action);
+ break;
+ }
+ }
+ }
+ }
+
+ public void getInsertActions(Document parent, CMDocument cmDocument, int index, int includeOptions, int validityChecking, List actionList)
+ {
+ // get the root element and doctype index (if any)
+ //
+ int doctypeIndex = -1;
+ DocumentType doctype = null;
+ Element rootElement = null;
+ NodeList nodeList = parent.getChildNodes();
+ int nodeListLength = nodeList.getLength();
+ for (int i = 0; i < nodeListLength; i++)
+ {
+ Node childNode = nodeList.item(i);
+ if (childNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ rootElement = (Element)childNode;
+ break;
+ }
+ else if (childNode.getNodeType() == Node.DOCUMENT_TYPE_NODE)
+ {
+ doctype = (DocumentType)childNode;
+ doctypeIndex = i;
+ }
+ }
+
+ // make sure that root elements are only added after the doctype (if any)
+ if (rootElement == null && index > doctypeIndex)
+ {
+ CMNamedNodeMap map = cmDocument.getElements();
+ int mapLength = map.getLength();
+ for (int i = 0; i < mapLength; i++)
+ {
+ CMNode cmNode = map.item(i);
+
+ boolean canAdd = true;
+ if (validityChecking == ModelQuery.VALIDITY_STRICT)
+ {
+ canAdd = doctype == null || doctype.getName().equals(cmNode.getNodeName());
+ }
+
+ if (canAdd)
+ {
+ Action action = new Action(ModelQueryAction.INSERT, parent, cmNode, index, index);
+ actionList.add(action);
+ }
+ }
+ }
+ }
+
+
+
+ public void getInsertChildNodeActionTable(Element parent, CMElementDeclaration ed, int validityChecking, Hashtable actionTable)
+ {
+ }
+
+
+ public void getReplaceActions(Element parent, CMElementDeclaration ed, int includeOptions, int validityChecking, List actionList)
+ {
+ CMValidator.MatchModelNode matchModelNode = modelQuery.getValidator().getMatchModel(ed, parent);
+ if (matchModelNode != null)
+ {
+ MatchModelVisitor visitor = new MatchModelVisitor(parent, actionList);
+ visitor.visitMatchModelNode(matchModelNode);
+ }
+ }
+
+ public void getReplaceActions(Element parent, CMElementDeclaration ed, List selectedChildren, int includeOptions, int validityChecking, List actionList)
+ {
+ int[] range = getRange(parent, selectedChildren);
+ if (range != null)
+ {
+ if (isContiguous(parent, range, selectedChildren))
+ {
+ List tempList = new Vector();
+ getReplaceActions(parent, ed, includeOptions, validityChecking, tempList);
+ if ((includeOptions & ModelQuery.INCLUDE_ENCLOSING_REPLACE_ACTIONS) != 0)
+ {
+ removeActionsNotContainingRange(tempList, range[0], range[1]);
+ }
+ else
+ {
+ removeActionsNotMatchingRange(tempList, range[0], range[1]);
+ }
+ actionList.addAll(tempList);
+ }
+ }
+
+ if (selectedChildren.size() == 1)
+ {
+ Node node = (Node)selectedChildren.get(0);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ Element childElement = (Element)node;
+ CMNode childEd = modelQuery.getCMElementDeclaration(childElement);
+ if (childEd != null)
+ {
+
+ CMNode childOrigin= modelQuery.getOrigin(childElement);
+
+ CMNodeList cmNodeList = childOrigin != null ?
+ (CMNodeList)childOrigin.getProperty("SubstitutionGroup") :
+ (CMNodeList)childEd.getProperty("SubstitutionGroup");
+
+ if (cmNodeList != null && cmNodeList.getLength() > 1)
+ {
+ int replaceIndex = getIndex(parent, childElement);
+ String childEdName = childEd.getNodeName();
+ for (int i = 0; i < cmNodeList.getLength(); i++)
+ {
+ CMNode substitution = cmNodeList.item(i);
+ if (!substitution.getNodeName().equals(childEdName) && !Boolean.TRUE.equals(substitution.getProperty("Abstract")))
+ {
+ Action action = new Action(ModelQueryAction.REPLACE, parent, cmNodeList.item(i), replaceIndex, replaceIndex);
+ actionList.add(action);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ // returns true if the selected nodes are contiguous
+ //
+ protected boolean isContiguous(Element parent, int[] range, List selectedNodeList)
+ {
+ boolean result = true;
+ NodeList nodeList = parent.getChildNodes();
+ int nodeListLength = nodeList.getLength();
+ for (int i = range[0]; i < range[1]; i++)
+ {
+ Node node = nodeList.item(i);
+ if (!isWhitespaceNode(node) && !selectedNodeList.contains(node))
+ {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ }
+
+
+ protected int[] getRange(Element parent, List list)
+ {
+ int[] result = null;
+ int first = -1;
+ int last = -1;
+
+ NodeList nodeList = parent.getChildNodes();
+ int nodeListLength = nodeList.getLength();
+ for (int i = 0; i < nodeListLength; i++)
+ {
+ Node node = nodeList.item(i);
+ if (list.contains(node))
+ {
+ first = (first == -1) ? i : Math.min(first, i);
+ last = Math.max(last, i);
+ }
+ }
+
+ if (first != -1 && last!= -1)
+ {
+ result = new int[2];
+ result[0] = first;
+ result[1] = last;
+ }
+ return result;
+ }
+
+
+ protected boolean isWhitespaceNode(Node node)
+ {
+ return node.getNodeType() == Node.TEXT_NODE &&
+ node.getNodeValue().trim().length() == 0;
+ }
+
+
+ protected int getIndex(Node parentNode, Node child)
+ {
+ NodeList nodeList = parentNode.getChildNodes();
+ int index = -1;
+ int size = nodeList.getLength();
+ for (int i = 0; i < size; i++)
+ {
+ if (nodeList.item(i) == child)
+ {
+ index = i;
+ break;
+ }
+ }
+ return index;
+ }
+
+
+ protected boolean isActionContainingRange(ModelQueryAction action, int startIndex, int endIndex)
+ {
+ int actionStartIndex = action.getStartIndex();
+ int actionEndIndex = action.getEndIndex();
+
+ return (actionStartIndex <= startIndex &&
+ actionEndIndex >= endIndex);
+ }
+
+
+ protected boolean isActionMatchingRange(ModelQueryAction action, int startIndex, int endIndex)
+ {
+ int actionStartIndex = action.getStartIndex();
+ int actionEndIndex = action.getEndIndex();
+ return (actionStartIndex == startIndex &&
+ actionEndIndex == endIndex);
+ }
+
+
+ protected void removeActionsNotContainingRange(List actionList, int startIndex, int endIndex)
+ {
+ for (int i = actionList.size() - 1; i >= 0; i--)
+ {
+ ModelQueryAction action = (ModelQueryAction)actionList.get(i);
+ if (!isActionContainingRange(action, startIndex, endIndex))
+ {
+ actionList.remove(i);
+ }
+ }
+ }
+
+
+ protected void removeActionsNotMatchingRange(List actionList, int startIndex, int endIndex)
+ {
+ for (int i = actionList.size() - 1; i >= 0; i--)
+ {
+ ModelQueryAction action = (ModelQueryAction)actionList.get(i);
+ if (!isActionMatchingRange(action, startIndex, endIndex))
+ {
+ actionList.remove(i);
+ }
+ }
+ }
+
+
+ public static class MatchModelVisitor
+ {
+ int indent;
+ int elementIndex;
+ Node parent;
+ List actionList;
+
+ public MatchModelVisitor(Node parent, List actionList)
+ {
+ this.parent = parent;
+ this.actionList = actionList;
+ }
+
+ public int indexOfNextElement(int start)
+ {
+ NodeList nodeList = parent.getChildNodes();
+ int length = nodeList.getLength();
+ int result = length;
+ for (int i = start; i < length; i++)
+ {
+ Node node = nodeList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ result = i;
+ break;
+ }
+ }
+ return result;
+ }
+
+ public void visitMatchModelNode(CMValidator.MatchModelNode matchModelNode)
+ {
+ int startIndex = indexOfNextElement(elementIndex);
+
+ String cmNodeName = matchModelNode.cmNode != null ? matchModelNode.cmNode.getNodeName() : "null";
+ //printIndented(indent, "+MatchModelNode : " + cmNodeName + " " + startIndex);
+
+ indent += 2;
+ for (Iterator iterator = matchModelNode.children.iterator(); iterator.hasNext(); )
+ {
+ CMValidator.MatchModelNode child = (CMValidator.MatchModelNode)iterator.next();
+ visitMatchModelNode(child);
+ }
+ indent -= 2;
+
+ if (matchModelNode.cmNode != null)
+ {
+ int nodeType = matchModelNode.cmNode.getNodeType();
+ if (nodeType == CMNode.GROUP)
+ {
+ CMGroup group = (CMGroup)matchModelNode.cmNode;
+ if (group.getOperator() == CMGroup.CHOICE)
+ {
+ addReplaceActions(matchModelNode, group, startIndex, elementIndex - 1);
+ }
+ }
+ else if (nodeType == CMNode.ELEMENT_DECLARATION)
+ {
+ elementIndex = startIndex + 1;
+ }
+ //printIndented(indent, "-MatchModelNode : " + cmNodeName + " " + (elementIndex - 1));
+ }
+ }
+
+ public void addReplaceActions(CMValidator.MatchModelNode matchModelNode, CMGroup group, int startIndex, int endIndex)
+ {
+ CMNode excludeCMNode = null;
+ if (matchModelNode.children.size() > 0)
+ {
+ CMValidator.MatchModelNode child = (CMValidator.MatchModelNode)matchModelNode.children.get(0);
+ excludeCMNode = child.cmNode;
+ }
+
+ CMNodeList nodeList = group.getChildNodes();
+ int size = nodeList.getLength();
+ for (int i = 0; i < size; i++)
+ {
+ CMNode alternative = nodeList.item(i);
+ if (alternative != excludeCMNode)
+ {
+ Action action = new Action(ModelQueryAction.REPLACE, parent, alternative, startIndex, endIndex);
+ actionList.add(action);
+ }
+ }
+ }
+ }
+
+ //public static void printIndented(int indent, String string)
+ //{
+ // for (int i = 0; i < indent; i++)
+ // {
+ // System.out.print(" ");
+ // }
+ // System.out.println(string);
+ //}
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryImpl.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryImpl.java
new file mode 100644
index 0000000000..befc4043de
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryImpl.java
@@ -0,0 +1,848 @@
+/*
+* Copyright (c) 2002 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Common Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/cpl-v10.html
+*
+* Contributors:
+* IBM - Initial API and implementation
+* Jens Lukowski/Innoopract - initial renaming/restructuring
+*
+*/
+package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.eclipse.wst.sse.core.internal.contentmodel.CMAnyElement;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMDataType;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMGroup;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMNamedNodeMap;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMNode;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMNodeList;
+import org.eclipse.wst.sse.core.internal.contentmodel.internal.modelqueryimpl.*;
+import org.eclipse.wst.sse.core.internal.contentmodel.internal.util.CMDataTypeValueHelper;
+import org.eclipse.wst.sse.core.internal.contentmodel.internal.util.DOMValidator;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQuery;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQueryAssociationProvider;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.extension.ModelQueryExtensionManager;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.CMVisitor;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.DOMNamespaceHelper;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceInfo;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceTable;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+
+/**
+ * This class implements a large portion of the ModelQuery interfaces.
+ * Some work is delegated to the DOMHelper, CMDocumentManager, and DOMValidator.
+ */
+public class ModelQueryImpl implements ModelQuery
+{
+ protected ModelQueryAssociationProvider modelQueryAssociationProvider;
+ protected ModelQueryActionHelper modelQueryActionHelper;
+ protected DOMValidator validator;
+ protected ModelQueryExtensionManagerImpl extensionManager;
+ protected CMDataTypeValueHelper valueHelper;
+ protected int editMode = EDIT_MODE_CONSTRAINED_STRICT;
+
+ public ModelQueryImpl(ModelQueryAssociationProvider modelQueryAssociationProvider)
+ {
+ this.modelQueryAssociationProvider = modelQueryAssociationProvider;
+ modelQueryActionHelper = createModelQueryActionHelper();
+ validator = new DOMValidator();
+ extensionManager = new ModelQueryExtensionManagerImpl();
+ valueHelper = new CMDataTypeValueHelper();
+ }
+
+ public int getEditMode()
+ {
+ return editMode;
+ }
+
+ public void setEditMode(int editMode)
+ {
+ this.editMode =editMode;
+ }
+
+
+ // factory methods
+ public ModelQueryActionHelper createModelQueryActionHelper()
+ {
+ return new ModelQueryActionHelper(this);
+ }
+
+ public DOMValidator getValidator()
+ {
+ return validator;
+ }
+
+ public CMDocument getCorrespondingCMDocument(Node node)
+ {
+ return modelQueryAssociationProvider.getCorrespondingCMDocument(node);
+ }
+
+ public CMNode getCMNode(Node node)
+ {
+ return modelQueryAssociationProvider.getCMNode(node);
+ }
+
+ public CMDataType getCMDataType(Text text)
+ {
+ return modelQueryAssociationProvider.getCMDataType(text);
+ }
+
+ public CMAttributeDeclaration getCMAttributeDeclaration(Attr attr)
+ {
+ return modelQueryAssociationProvider.getCMAttributeDeclaration(attr);
+ }
+
+ public CMElementDeclaration getCMElementDeclaration(Element element)
+ {
+ return modelQueryAssociationProvider.getCMElementDeclaration(element);
+ }
+
+ public CMDocumentManager getCMDocumentManager()
+ {
+ CMDocumentManager result = null;
+ if (modelQueryAssociationProvider instanceof XMLAssociationProvider)
+ {
+ XMLAssociationProvider xmlAssociationProvider = (XMLAssociationProvider)modelQueryAssociationProvider;
+ result = xmlAssociationProvider.getCMDocumentManager();
+ }
+ return result;
+ }
+
+
+ /**
+ * @deprected - use 3 arg version below
+ */
+ public List getCMDocumentList(Element element, String uri)
+ {
+ return Collections.EMPTY_LIST;
+ }
+
+ public List getCMDocumentList(Element element, CMElementDeclaration ed, String uri)
+ {
+ List result = new Vector();
+ if (modelQueryAssociationProvider instanceof XMLAssociationProvider)
+ {
+ XMLAssociationProvider xmlAssociationProvider = (XMLAssociationProvider)modelQueryAssociationProvider;
+
+ // todo... revist... handle each ##thing explicitly
+ //
+ if (uri == null)
+ {
+ uri = "##any";
+ }
+
+ if (uri.equals("##targetNamespace"))
+ {
+ CMDocument cmDocument = (CMDocument)ed.getProperty("CMDocument");
+ if (cmDocument != null)
+ {
+ result.add(cmDocument);
+ }
+ }
+ else if (uri.equals("##any") || uri.equals("##other"))
+ {
+ String excludedURI = null;
+ if (uri.equals("##other"))
+ {
+ CMDocument cmDocument = (CMDocument)ed.getProperty("CMDocument");
+ if (cmDocument != null)
+ {
+ excludedURI = (String)cmDocument.getProperty("http://org.eclipse.wst/cm/properties/targetNamespaceURI");
+ }
+ }
+
+ // in this case we should consider all of the schema related to this document
+ //
+ NamespaceTable namespaceTable = new NamespaceTable(element.getOwnerDocument());
+ namespaceTable.addElementLineage(element);
+ List list = namespaceTable.getNamespaceInfoList();
+ for (Iterator i = list.iterator(); i.hasNext();)
+ {
+ NamespaceInfo info = (NamespaceInfo)i.next();
+ if (info.uri != null && !info.uri.equals(excludedURI))
+ {
+ CMDocument document = xmlAssociationProvider.getCMDocument(info.uri, info.locationHint, "XSD");
+ if (document != null)
+ {
+ result.add(document);
+ }
+ }
+ }
+ }
+ else
+ {
+ CMDocument document = xmlAssociationProvider.getCMDocument(element, uri);
+ if (document != null)
+ {
+ result.add(document);
+ }
+ }
+ }
+ return result;
+ }
+
+
+ public CMDocument getCMDocument(Element element, String uri)
+ {
+
+ CMDocument result = null;
+ if (modelQueryAssociationProvider instanceof XMLAssociationProvider)
+ {
+ XMLAssociationProvider xmlAssociationProvider = (XMLAssociationProvider)modelQueryAssociationProvider;
+ result = xmlAssociationProvider.getCMDocument(element, uri);
+ }
+ //ContentModelManager.println("ModelQueryImpl.getCMDocument(" + element.getNodeName() + ", " + uri + ") = " + result);
+ return result;
+ }
+
+ public boolean isContentValid(Element element)
+ {
+ CMElementDeclaration ed = getCMElementDeclaration(element);
+ return isContentValid(ed, element);
+ }
+
+ public boolean isContentValid(CMElementDeclaration ed, Element element)
+ {
+ boolean result = true;
+ if (ed != null)
+ {
+ // first check to see if all the required attributes are present
+ //
+ CMNamedNodeMap map = ed.getAttributes();
+ int mapLength = map.getLength();
+ for (int i = 0; i < mapLength; i++)
+ {
+ CMAttributeDeclaration ad = (CMAttributeDeclaration)map.item(i);
+ String attributeName = DOMNamespaceHelper.computeName(ad, element, null);
+ if (ad.getUsage() == CMAttributeDeclaration.REQUIRED)
+ {
+ Attr attr = element.getAttributeNode(attributeName);
+ if (attr == null)
+ {
+ result = false;
+ break;
+ }
+ }
+ }
+
+ // now check to see of the children validate properly
+ //
+ if (result)
+ {
+ CMNode[] originArray = getOriginArray(element);
+ result = originArray != null && originArray.length == element.getChildNodes().getLength();
+ }
+ }
+ return result;
+ }
+
+
+ public CMNode getOrigin(Node node)
+ {
+ CMNode result = null;
+ // todo... make sure parent is right
+ //
+ Node parentNode = getParentOrOwnerNode(node);
+ if (parentNode != null && parentNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ Element parentElement = (Element)parentNode;
+ CMNode[] array = getOriginArray(parentElement);
+ if (array != null)
+ {
+ int index = getIndexOfNode(parentElement.getChildNodes(), node);
+ if (index < array.length)
+ {
+ result = array[index];
+ }
+ }
+ }
+ return result;
+ }
+
+ public CMNode[] getOriginArray(Element element)
+ {
+ CMElementDeclaration ed = getCMElementDeclaration(element);
+ return (ed != null) ? getValidator().getOriginArray(ed, element) : null;
+ }
+
+ public int getIndexOfNode(NodeList nodeList, Node node)
+ {
+ int result = -1;
+ int size = nodeList.getLength();
+ for (int i = 0; i < size; i++)
+ {
+ if (nodeList.item(i) == node)
+ {
+ result = i;
+ break;
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns a list of all CMNode 'meta data' that may be potentially added to the element.
+ */
+ public List getAvailableContent(Element element, CMElementDeclaration ed, int includeOptions)
+ {
+ AvailableContentCMVisitor visitor = new AvailableContentCMVisitor(element, ed);
+ List list = visitor.computeAvailableContent(includeOptions);
+ if (extensionManager != null)
+ {
+ extensionManager.filterAvailableElementContent(list, element, ed);
+ }
+ return list;
+ }
+
+
+ public boolean canInsert(Element parent, CMNode cmNode, int index, int validityChecking)
+ {
+ boolean result = true;
+ CMElementDeclaration ed = getCMElementDeclaration(parent);
+ if (ed != null)
+ {
+ result = canInsert(parent, ed, cmNode, index, validityChecking);
+ }
+ return result;
+ }
+
+
+ public boolean canInsert(Element parent, CMElementDeclaration ed, CMNode cmNode, int index, int validityChecking)
+ {
+ return canInsert(parent, ed, cmNode, index, validityChecking, null);
+ }
+
+ protected boolean canInsert(Element parent, CMElementDeclaration ed, CMNode cmNode, int index, int validityChecking, Object reuseableData)
+ {
+ boolean result = true;
+ switch (cmNode.getNodeType())
+ {
+ case CMNode.ATTRIBUTE_DECLARATION :
+ {
+ String attributeName = DOMNamespaceHelper.computeName(cmNode, parent, null);
+ result = parent.getAttributeNode(attributeName) == null;
+ break;
+ }
+ case CMNode.ELEMENT_DECLARATION :
+ case CMNode.GROUP :
+ {
+ if (validityChecking == VALIDITY_STRICT)
+ {
+ // create list
+ List contentSpecificationList = null;
+ if (reuseableData != null)
+ {
+ contentSpecificationList = (List)reuseableData;
+ }
+ else
+ {
+ contentSpecificationList = getValidator().createContentSpecificationList(parent, ed);
+ }
+ result = getValidator().canInsert(ed, contentSpecificationList, index, cmNode);
+ }
+ break;
+ }
+ case CMNode.DATA_TYPE :
+ {
+ int contentType = ed.getContentType();
+ result = (contentType == CMElementDeclaration.MIXED ||
+ contentType == CMElementDeclaration.PCDATA ||
+ contentType == CMElementDeclaration.ANY);
+ break;
+ }
+ default :
+ {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ }
+
+ public boolean canInsert(Element parent, List cmNodeList, int index, int validityChecking)
+ {
+ // todo
+ return true;
+ }
+
+
+ public boolean canRemove(Node node, int validityChecking)
+ {
+ boolean result = true;
+ if (validityChecking == VALIDITY_STRICT)
+ {
+ int nodeType = node.getNodeType();
+ switch (nodeType)
+ {
+ case Node.ATTRIBUTE_NODE:
+ {
+ CMAttributeDeclaration ad = getCMAttributeDeclaration((Attr)node);
+ if (ad != null)
+ {
+ result = (ad.getUsage() == CMAttributeDeclaration.OPTIONAL);
+ }
+ break;
+ }
+ case Node.ELEMENT_NODE:
+ {
+ Node parentNode = node.getParentNode();
+ if (parentNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ Element parentElement = (Element)parentNode;
+ CMElementDeclaration ed = getCMElementDeclaration(parentElement);
+ if (ed != null)
+ {
+ List contentSpecificationList = getValidator().createContentSpecificationList(parentElement, ed);
+ int index = getIndexOfNode(parentElement.getChildNodes(), node);
+ result = getValidator().canRemove(ed, contentSpecificationList, index);
+ }
+ }
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+
+ public boolean canRemove(List nodeList, int validityChecking)
+ {
+ boolean result = true;
+
+ if (validityChecking == VALIDITY_STRICT)
+ {
+ Element parentElement = null;
+ List childList = null;
+
+ for (Iterator i = nodeList.iterator(); i.hasNext(); )
+ {
+ Node node = (Node)i.next();
+
+ if (parentElement == null)
+ {
+ parentElement = getParentOrOwnerElement(node);
+ }
+ else if (parentElement != getParentOrOwnerElement(node))
+ {
+ // make sure the parent are the same
+ result = false;
+ break;
+ }
+
+ if (parentElement == null)
+ {
+ result = true;
+ break;
+ }
+
+ int nodeType = node.getNodeType();
+ if (nodeType == Node.ATTRIBUTE_NODE)
+ {
+ if (!canRemove(node, validityChecking))
+ {
+ result = false;
+ break;
+ }
+ }
+ else
+ {
+ if (childList == null)
+ {
+ childList = nodeListToList(parentElement.getChildNodes());
+ }
+ childList.remove(node);
+ }
+ }
+
+ if (result && childList != null)
+ {
+ CMElementDeclaration ed = getCMElementDeclaration(parentElement);
+ if (ed != null)
+ {
+ List contentSpecificationList = getValidator().createContentSpecificationList(childList, ed);
+ result = getValidator().isValid(ed, contentSpecificationList);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public boolean canReplace(Element parent, int startIndex, int endIndex, CMNode cmNode, int validityChecking)
+ {
+ return true;
+ }
+
+ public boolean canReplace(Element parent, int startIndex, int endIndex, List cmNodeList, int validityChecking)
+ {
+ return true;
+ }
+
+ /**
+ * This method is experimental... use at your own risk
+ */
+ public boolean canWrap(Element childElement, CMElementDeclaration wrapElement, int validityChecking)
+ {
+ boolean result = true;
+ Node parentNode = childElement.getParentNode();
+ if (parentNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ Element parentElement = (Element)parentNode;
+ CMElementDeclaration parentEd = getCMElementDeclaration(parentElement);
+ if (parentEd != null)
+ {
+ if (validityChecking == VALIDITY_STRICT)
+ {
+ int index = getIndexOfNode(parentElement.getChildNodes(), childElement);
+
+ List contentSpecificationList = getValidator().createContentSpecificationList(parentElement, parentEd);
+ List subList = contentSpecificationList.subList(index, index + 1);
+ result = getValidator().canReplace(parentEd, contentSpecificationList, index, index, wrapElement);
+ if (result)
+ {
+ result = getValidator().isValid(wrapElement, subList);
+ }
+ }
+ }
+ }
+ else
+ {
+ result = false;
+ }
+ return result;
+ }
+
+ public void getInsertActions(Element parent, CMElementDeclaration ed, int index, int includeOptions, int validityChecking, List actionList)
+ {
+ modelQueryActionHelper.getInsertActions(parent, ed, index, includeOptions, validityChecking, actionList);
+ }
+
+ public void getInsertActions(Document parent, CMDocument cmDocument, int index, int includeOptions, int validityChecking, List actionList)
+ {
+ modelQueryActionHelper.getInsertActions(parent, cmDocument, index, includeOptions, validityChecking, actionList);
+ }
+
+ public void getReplaceActions(Element parent, CMElementDeclaration ed, int includeOptions, int validityChecking, List actionList)
+ {
+ modelQueryActionHelper.getReplaceActions(parent, ed, includeOptions, validityChecking, actionList);
+ }
+
+ public void getReplaceActions(Element parent, CMElementDeclaration ed, List selectedChildren, int includeOptions, int validityChecking, List actionList)
+ {
+ modelQueryActionHelper.getReplaceActions(parent, ed, selectedChildren, includeOptions, validityChecking, actionList);
+ }
+
+ public void getInsertChildNodeActionTable(Element parent, CMElementDeclaration ed, int validityChecking, Hashtable actionTable)
+ {
+ modelQueryActionHelper.getInsertChildNodeActionTable(parent, ed, validityChecking, actionTable);
+ }
+
+ public void getActionTable(Element parent, CMElementDeclaration ed, int index, int validityChecking, Hashtable actionTable)
+ {
+ //modelQueryActionHelper.getAllActions(parent, ed, validityChecking, actionList);
+ }
+
+
+ // some helper methods
+ //
+ protected Node getParentOrOwnerNode(Node node)
+ {
+ return (node.getNodeType() == Node.ATTRIBUTE_NODE) ?
+ ((Attr)node).getOwnerElement() :
+ node.getParentNode();
+ }
+
+ protected Element getParentOrOwnerElement(Node node)
+ {
+ Node parent = getParentOrOwnerNode(node);
+ return (parent.getNodeType() == Node.ELEMENT_NODE) ? (Element)parent : null;
+ }
+
+
+ protected List nodeListToList(NodeList nodeList)
+ {
+ int size = nodeList.getLength();
+ Vector v = new Vector(size);
+ for (int i = 0; i < size; i++)
+ {
+ v.add(nodeList.item(i));
+ }
+ return v;
+ }
+
+ /**
+ protected List getCMNodeList(NodeList nodeList)
+ {
+ int size = nodeList.getLength();
+ Vector v = new Vector(size);
+ for (int i = 0; i < size; i++)
+ {
+ v.add(getCMNode(nodeList.item(i));
+ }
+ return v;
+ }
+ */
+
+ public class AvailableContentCMVisitor extends CMVisitor
+ {
+ public Hashtable childNodeTable = new Hashtable();
+ public Hashtable attributeTable = new Hashtable();
+ public Element rootElement;
+ public CMElementDeclaration rootElementDeclaration;
+ public boolean isRootVisited;
+ protected boolean includeSequenceGroups;
+
+ public AvailableContentCMVisitor(Element rootElement, CMElementDeclaration rootElementDeclaration)
+ {
+ this.rootElement = rootElement;
+ this.rootElementDeclaration = rootElementDeclaration;
+ }
+
+ protected String getKey(CMNode cmNode)
+ {
+ String key = cmNode.getNodeName();
+ CMDocument cmDocument = (CMDocument)cmNode.getProperty("CMDocument");
+ if (cmDocument != null)
+ {
+ String namespaceURI = (String)cmDocument.getProperty("http://org.eclipse.wst/cm/properties/targetNamespaceURI");
+ if (namespaceURI != null)
+ {
+ key = "[" + namespaceURI + "]" + key;
+ }
+ }
+ return key;
+ }
+
+ public List computeAvailableContent(int includeOptions)
+ {
+ Vector v = new Vector();
+
+ int contentType = rootElementDeclaration.getContentType();
+ includeSequenceGroups = ((includeOptions & INCLUDE_SEQUENCE_GROUPS) != 0);
+ visitCMNode(rootElementDeclaration);
+
+ if ((includeOptions & INCLUDE_ATTRIBUTES) != 0)
+ {
+ v.addAll(attributeTable.values());
+ CMAttributeDeclaration nillableAttribute = (CMAttributeDeclaration)rootElementDeclaration.getProperty("http://org.eclipse.wst/cm/properties/nillable");
+ if (nillableAttribute != null)
+ {
+ v.add(nillableAttribute);
+ }
+ }
+
+ if ((includeOptions & INCLUDE_CHILD_NODES) != 0)
+ {
+ if (contentType == CMElementDeclaration.MIXED ||
+ contentType == CMElementDeclaration.ELEMENT)
+ {
+ v.addAll(childNodeTable.values());
+ }
+ else if (contentType == CMElementDeclaration.ANY)
+ {
+ CMDocument cmDocument = (CMDocument)rootElementDeclaration.getProperty("CMDocument");
+ if (cmDocument != null)
+ {
+ CMNamedNodeMap elements = cmDocument.getElements();
+ for (Iterator i = elements.iterator(); i.hasNext(); )
+ {
+ v.add(i.next());
+ }
+ }
+ }
+
+ if (contentType == CMElementDeclaration.MIXED ||
+ contentType == CMElementDeclaration.PCDATA ||
+ contentType == CMElementDeclaration.ANY)
+ {
+ CMDataType dataType = rootElementDeclaration.getDataType();
+ if (dataType != null)
+ {
+ v.add(dataType);
+ }
+ }
+ }
+ return v;
+ }
+
+ public void visitCMAnyElement(CMAnyElement anyElement)
+ {
+ String uri = anyElement.getNamespaceURI();
+ List list = getCMDocumentList(rootElement, rootElementDeclaration, uri);
+ for (Iterator iterator = list.iterator(); iterator.hasNext(); )
+ {
+ CMDocument cmdocument = (CMDocument)iterator.next();
+ if (cmdocument != null)
+ {
+ CMNamedNodeMap map = cmdocument.getElements();
+ int size = map.getLength();
+ for (int i = 0; i < size; i++)
+ {
+ CMNode ed = map.item(i);
+
+ childNodeTable.put(getKey(ed), ed);
+ }
+ }
+ }
+ }
+
+ public void visitCMAttributeDeclaration(CMAttributeDeclaration ad)
+ {
+ super.visitCMAttributeDeclaration(ad);
+ attributeTable.put(ad.getNodeName(), ad);
+ }
+
+ public void visitCMElementDeclaration(CMElementDeclaration ed)
+ {
+ if (ed == rootElementDeclaration && !isRootVisited)
+ {
+ isRootVisited = true;
+ super.visitCMElementDeclaration(ed);
+ }
+ else
+ {
+ if (!Boolean.TRUE.equals(ed.getProperty("Abstract")))
+ {
+ childNodeTable.put(getKey(ed), ed);
+ }
+
+ CMNodeList substitutionGroup = (CMNodeList)ed.getProperty("SubstitutionGroup");
+ if (substitutionGroup != null)
+ {
+ handleSubstitutionGroup(substitutionGroup);
+ }
+ }
+ }
+
+ protected void handleSubstitutionGroup(CMNodeList substitutionGroup)
+ {
+ int substitutionGroupLength = substitutionGroup.getLength();
+ if (substitutionGroupLength > 1)
+ {
+ for (int i = 0; i < substitutionGroupLength; i++)
+ {
+ CMNode ed = substitutionGroup.item(i);
+ if (!Boolean.TRUE.equals(ed.getProperty("Abstract")))
+ {
+ childNodeTable.put(getKey(ed), ed);
+ }
+ }
+ }
+ }
+
+ public void visitCMGroup(CMGroup group)
+ {
+ if (includeSequenceGroups)
+ {
+ if (group.getOperator() == CMGroup.SEQUENCE &&
+ group.getChildNodes().getLength() > 1 &&
+ includesRequiredContent(group))
+ {
+ childNodeTable.put(group, group);
+ }
+ }
+ super.visitCMGroup(group);
+ }
+
+ public boolean includesRequiredContent(CMGroup group)
+ {
+ List list = getValidator().createContentSpecificationList(group);
+ return list.size() > 1;
+ }
+ }
+
+
+ /**
+ * @deprected - use getPossibleDataTypeValues()
+ */
+ public List getDataTypeValues(Element element, CMNode cmNode)
+ {
+ return Arrays.asList(getPossibleDataTypeValues(element, cmNode));
+ }
+
+ /**
+ * This methods return an array of possible values corresponding to the datatype of the CMNode (either an CMAttributeDeclaration or a CMElementDeclaration)
+ */
+ public String[] getPossibleDataTypeValues(Element element, CMNode cmNode)
+ {
+ List list = new Vector();
+
+ if (cmNode != null)
+ {
+ CMDataType dataType = null;
+ if (cmNode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION)
+ {
+ dataType = ((CMAttributeDeclaration)cmNode).getAttrType();
+ }
+ else if (cmNode.getNodeType() == CMNode.ELEMENT_DECLARATION)
+ {
+ dataType = ((CMElementDeclaration)cmNode).getDataType();
+ }
+
+ String[] enumeratedValues = dataType != null ? dataType.getEnumeratedValues() : null;
+ if (enumeratedValues != null)
+ {
+ for (int i = 0; i < enumeratedValues.length; i++)
+ {
+ list.add(enumeratedValues[i]);
+ }
+ }
+ }
+
+ addValuesForXSIType(element, cmNode, list);
+
+ if (extensionManager != null)
+ {
+ list.addAll(extensionManager.getDataTypeValues(element, cmNode));
+ }
+
+ int listSize = list.size();
+ String[] result = new String[listSize];
+ for (int i = 0; i < listSize; i++)
+ {
+ result[i] = (String)list.get(i);
+ }
+ return result;
+ }
+
+
+ protected void addValuesForXSIType(Element element, CMNode cmNode, List list)
+ {
+ if (cmNode != null && cmNode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION)
+ {
+ CMAttributeDeclaration ad = (CMAttributeDeclaration)cmNode;
+ if (valueHelper.isXSIType(ad))
+ {
+ NamespaceTable table = new NamespaceTable(element.getOwnerDocument());
+ table.addElementLineage(element);
+ list.addAll(valueHelper.getQualifiedXSITypes(ad, table));
+ }
+ }
+ }
+
+
+ public ModelQueryExtensionManager getExtensionManager()
+ {
+ return extensionManager;
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/SimpleAssociationProvider.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/SimpleAssociationProvider.java
new file mode 100644
index 0000000000..b8b653cc92
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/SimpleAssociationProvider.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2002 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Common Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/cpl-v10.html
+*
+* Contributors:
+* IBM - Initial API and implementation
+* Jens Lukowski/Innoopract - initial renaming/restructuring
+*
+*/
+package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl;
+
+import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQueryCMProvider;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+/**
+ *
+ */
+public class SimpleAssociationProvider extends BaseAssociationProvider
+{
+ protected ModelQueryCMProvider modelQueryCMProvider;
+
+ public SimpleAssociationProvider(ModelQueryCMProvider modelQueryCMProvider)
+ {
+ this.modelQueryCMProvider = modelQueryCMProvider;
+ }
+
+ public CMDocument getCorrespondingCMDocument(Node node)
+ {
+ return modelQueryCMProvider.getCorrespondingCMDocument(node);
+ }
+
+ public CMElementDeclaration getCMElementDeclaration(Element element)
+ {
+ CMElementDeclaration result = null;
+ CMDocument cmDocument = getCorrespondingCMDocument(element);
+ if (cmDocument != null)
+ {
+ result = (CMElementDeclaration)cmDocument.getElements().getNamedItem(element.getNodeName());
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/XMLAssociationProvider.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/XMLAssociationProvider.java
new file mode 100644
index 0000000000..3313dfaa7d
--- /dev/null
+++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/XMLAssociationProvider.java
@@ -0,0 +1,402 @@
+/*
+* Copyright (c) 2002 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Common Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/cpl-v10.html
+*
+* Contributors:
+* IBM - Initial API and implementation
+* Jens Lukowski/Innoopract - initial renaming/restructuring
+*
+*/
+package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.wst.sse.core.internal.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.sse.core.internal.contentmodel.CMNode;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager;
+import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentReferenceProvider;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.CMDocumentCache;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.DOMNamespaceHelper;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceInfo;
+import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceTable;
+import org.w3c.dom.Attr;
+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 abstract class XMLAssociationProvider extends BaseAssociationProvider implements CMDocumentReferenceProvider
+{
+ protected CMDocumentCache cmDocumentCache;
+ protected CMDocumentManagerImpl documentManager;
+
+ public XMLAssociationProvider(CMDocumentCache cmDocumentCache)
+ {
+ this.cmDocumentCache = cmDocumentCache;
+ documentManager = new CMDocumentManagerImpl(cmDocumentCache, this);
+ }
+
+ public CMDocumentManager getCMDocumentManager()
+ {
+ return documentManager;
+ }
+
+
+ public static String[] getDoctypeInfo(Document document)
+ {
+ String[] result = null;
+ DocumentType doctype = document.getDoctype();
+
+ // defect 206833 ... here we test for DTDs that are declared inline
+ // since we currently have no way of making use of inline DTDs we ingore them
+ // so that the implict DTD (if any) can be used
+ if (doctype != null && (doctype.getPublicId() != null || doctype.getSystemId() != null))
+ {
+ result = new String[2];
+ result[0] = doctype.getPublicId();
+ result[1] = doctype.getSystemId();
+ }
+ else if (getImplictDoctype(document) != null)
+ {
+ result = getImplictDoctype(document);
+ }
+ return result;
+ }
+
+
+ protected static String[] getImplictDoctype(Document document)
+ {
+ String[] result = null;
+ /*
+ DOMExtension domExtension = DOMExtensionProviderRegistry.getInstance().getDOMExtension(document);
+ if (domExtension != null)
+ {
+ result = domExtension.getImplicitDoctype();
+ }*/
+ return result;
+ }
+
+ public CMDocument getCorrespondingCMDocument(Node node)
+ {
+ return getCorrespondingCMDocument(node, true);
+ }
+
+ protected CMDocument getCorrespondingCMDocument(Node node, boolean getDocumentFromCMNode)
+ {
+ CMDocument result = null;
+ try
+ {
+ Document document = node.getNodeType() == Node.DOCUMENT_NODE ? (Document)node : node.getOwnerDocument();
+
+ String[] doctypeInfo = getDoctypeInfo(document);
+
+ if (doctypeInfo != null)
+ {
+ result = getCMDocument(doctypeInfo[0], doctypeInfo[1], "DTD");
+ }
+ // defect 211236 ... in some cases calling this method can result in a cycle
+ // we use the getDocumentFromCMNode as a flag to avoid this
+ // TODO... see if there is a way to re-organize to avoid the need for this flag
+ else if (getDocumentFromCMNode)
+ {
+ CMNode cmNode = getCMNode(node);
+ if (cmNode != null)
+ {
+ // todo... add a getCMDocument() methods to CMNode
+ // for now use the getProperty interface
+ result = (CMDocument)cmNode.getProperty("CMDocument");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+
+ public CMDocument getCMDocument(Element element, String uri)
+ {
+ CMDocument result = null;
+ NamespaceTable namespaceTable = new NamespaceTable(element.getOwnerDocument());
+ namespaceTable.addElementLineage(element);
+ NamespaceInfo namespaceInfo = namespaceTable.getNamespaceInfoForURI(uri);
+ if (namespaceInfo != null)
+ {
+ result = getCMDocument(namespaceInfo.uri, namespaceInfo.locationHint, "XSD");
+ }
+ return result;
+ }
+
+
+ public CMDocument getCMDocument(String publicId, String systemId, String type)
+ {
+ //String resolvedGrammarURI = resolveGrammarURI(document, publicId, systemId);
+ return documentManager.getCMDocument(publicId, systemId, type);
+ }
+
+ //public CMDocument getCMDocument(Document document, String publicId, String systemId)
+ //{
+ // //String resolvedGrammarURI = resolveGrammarURI(document, publicId, systemId);
+ // return documentManager.getCMDocument(publicId, systemId);
+ //}
+
+ public String resolveGrammarURI(String publicId, String systemId)
+ {
+ return resolveGrammarURI(null, publicId, systemId);
+ }
+
+
+ /**
+ * This method should be specialized in order to implement specialized uri resolution
+ */
+ protected String resolveGrammarURI(Document document, String publicId, String systemId)
+ {
+ return systemId;
+ }
+
+
+ public CMElementDeclaration getCMElementDeclaration(Element element)
+ {
+ CMElementDeclaration result = null;
+ Document document = element.getOwnerDocument();
+ String[] doctypeInfo = getDoctypeInfo(document);
+ if (doctypeInfo != null)
+ {
+ // we have detected doctype information so we assume that we can locate the CMElementDeclaration
+ // in the CMDocument's table of global elements
+ CMDocument cmDocument = getCorrespondingCMDocument(element, false);
+
+ // TODO... consider replacing above with
+ // CMDocument cmDocument = getCMDocument(document, doctypeInfo[0], doctypeInfo[1]);
+
+ if (cmDocument != null)
+ {
+ result = (CMElementDeclaration)cmDocument.getElements().getNamedItem(element.getNodeName());
+
+ // this is a hack to get our xsl code assist working... we might want to handle similar
+ // grammar behaviour via some established model query setting
+ if (result == null && getImplictDoctype(document) != null)
+ {
+ Node parent = element.getParentNode();
+ if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE)
+ {
+ result = getCMElementDeclaration((Element)parent);
+ }
+ }
+ }
+ }
+ else
+ {
+ // here we use a namespaceTable to consider if the root element has any namespace information
+ //
+ NamespaceTable namespaceTable = new NamespaceTable(element.getOwnerDocument());
+ List list = NamespaceTable.getElementLineage(element);
+ Element rootElement = (Element)list.get(0);
+ namespaceTable.addElement(rootElement);
+
+ if (namespaceTable.isNamespaceEncountered())
+ {
+ // we assume that this is an XMLSchema style namespace aware document
+ result = getCMElementDeclaration(element, list, namespaceTable);
+ }
+ else
+ {
+ // we assume that this is an inferred CMDocument for a DTD style 'namespaceless' document
+ CMDocument cmDocument = getCMDocument("", "", "DTD");
+ if (cmDocument != null)
+ {
+ result = (CMElementDeclaration)cmDocument.getElements().getNamedItem(element.getNodeName());
+ }
+ }
+ }
+ return result;
+ }
+
+
+ protected CMElementDeclaration getCMElementDeclaration(Element targetElement, List list, NamespaceTable namespaceTable)
+ {
+ CMElementDeclaration currentED = null;
+ try
+ {
+ int listSize = list.size();
+ for (int i = 0; i < listSize; i++)
+ {
+ Element element = (Element)list.get(i);
+
+ if (i != 0)
+ {
+ namespaceTable.addElement(element);
+ }
+
+ String nodeName = element.getNodeName();
+ String unprefixedName = DOMNamespaceHelper.getUnprefixedName(nodeName);
+ String prefix = DOMNamespaceHelper.getPrefix(nodeName);
+
+ CMElementDeclaration ed = null;
+
+ // see if the element is a local of the currentED
+ //
+ if (currentED != null)
+ {
+ ed = (CMElementDeclaration)currentED.getLocalElements().getNamedItem(unprefixedName);
+ }
+
+ if (ed == null)
+ {
+ NamespaceInfo namespaceInfo = namespaceTable.getNamespaceInfoForPrefix(prefix);
+ if (namespaceInfo != null)
+ {
+ CMDocument cmDocument = getCMDocument(namespaceInfo.uri, namespaceInfo.locationHint, "XSD");
+ if (cmDocument != null)
+ {
+ ed = (CMElementDeclaration)cmDocument.getElements().getNamedItem(unprefixedName);
+ }
+ }
+ }
+ currentED = ed;
+
+ // handle XSIType
+ if (currentED != null)
+ {
+ CMElementDeclaration derivedED = getDerivedCMElementDeclaration(element, currentED, namespaceTable);
+ if (derivedED != null)
+ {
+ currentED = derivedED;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ return currentED;
+ }
+
+
+ protected CMElementDeclaration getDerivedCMElementDeclaration(Element element, CMElementDeclaration ed, NamespaceTable namespaceTable)
+ {
+ CMElementDeclaration result = null;
+ String xsiPrefix = namespaceTable.getPrefixForURI("http://www.w3.org/2001/XMLSchema-instance");
+ if (xsiPrefix != null)
+ {
+ String xsiTypeValue = element.getAttribute(xsiPrefix + ":type");
+ if (xsiTypeValue != null)
+ {
+ String typePrefix = DOMNamespaceHelper.getPrefix(xsiTypeValue);
+ String typeName = DOMNamespaceHelper.getUnprefixedName(xsiTypeValue);
+ String typeURI = namespaceTable.getURIForPrefix(typePrefix);
+ String uriQualifiedTypeName = typeName;
+ if (typeURI != null && typeURI.length() > 0)
+ {
+ uriQualifiedTypeName = "[" + typeURI + "]" + typeName;
+ }
+ result = (CMElementDeclaration)ed.getProperty("DerivedElementDeclaration=" + uriQualifiedTypeName);
+ }
+ }
+ return result;
+ }
+
+
+ public CMAttributeDeclaration getCMAttributeDeclaration(Attr attr)
+ {
+ CMAttributeDeclaration result = null;
+ Element element = attr.getOwnerElement();
+ if (element != null)
+ {
+ CMElementDeclaration ed = getCMElementDeclaration(element);
+ if (ed != null)
+ {
+ result = (CMAttributeDeclaration)ed.getAttributes().getNamedItem(attr.getName());
+ if (result == null)
+ {
+ // try to get the unprefixed name
+ String name = DOMNamespaceHelper.getUnprefixedName(attr.getName());
+ result = (CMAttributeDeclaration)ed.getAttributes().getNamedItem(name);
+ }
+ if (result == null)
+ {
+ // todo... perhaps this is a globally defined attribute...
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * This method returns a list of CMDocumentReferences associated with a particular node or subtree
+ */
+ public List getCMDocumentReferences(Node node, boolean deep)
+ {
+ List result = new ArrayList();
+ Document document = (node.getNodeType() == Node.DOCUMENT_NODE) ? (Document)node : node.getOwnerDocument();
+ DocumentType doctype = document.getDoctype();
+ // defect 206833 ... here we test for DTDs that are declared inline
+ // since we currently have no way of making use of inline DTDs we ingore them
+ // so that the implict DTD (if any) can be used
+ if (doctype != null && (doctype.getPublicId() != null || doctype.getSystemId() != null))
+ {
+ String uri = resolveGrammarURI(document, doctype.getPublicId(), doctype.getSystemId());
+ result.add(new CMDocumentReferenceImpl(doctype.getPublicId(), uri));
+ }
+ else if (getImplictDoctype(document) != null)
+ {
+ String[] implicitDoctype = getImplictDoctype(document);
+ String uri = resolveGrammarURI(document, implicitDoctype[0], implicitDoctype[1]);
+ result.add(new CMDocumentReferenceImpl(implicitDoctype[0], uri));
+ }
+ else
+ {
+ NamespaceTable namespaceTable = new NamespaceTable(document);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ namespaceTable.addElement((Element)node);
+ }
+ if (deep)
+ {
+ addChildElementsToNamespaceTable(node, namespaceTable);
+ }
+ List list = namespaceTable.getNamespaceInfoList();
+ for (Iterator i = list.iterator(); i.hasNext();)
+ {
+ NamespaceInfo info = (NamespaceInfo) i.next();
+ String uri = resolveGrammarURI(document, info.uri, info.locationHint);
+ result.add(new CMDocumentReferenceImpl(info.uri, uri));
+ }
+ }
+ return result;
+ }
+
+ protected void addChildElementsToNamespaceTable(Node node, NamespaceTable namespaceTable)
+ {
+ NodeList nodeList = node.getChildNodes();
+ if (nodeList != null)
+ {
+ int nodeListLength = nodeList.getLength();
+ for (int i = 0; i < nodeListLength; i++)
+ {
+ Node childNode = nodeList.item(i);
+ if (childNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ namespaceTable.addElement((Element)childNode);
+ addChildElementsToNamespaceTable(childNode, namespaceTable);
+ }
+ }
+ }
+ }
+}

Back to the top