blob: cb8c84c320543f25cd45be7cf42ca49bee10118e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.xsd.ui.internal.util;
import java.util.ArrayList;
import org.eclipse.wst.sse.core.internal.format.IStructuredFormatProcessor;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.eclipse.wst.xml.core.internal.provisional.format.FormatProcessorXML;
import org.eclipse.xsd.util.XSDConstants;
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;
// issue (cs) remove this class!!
public class XSDDOMHelper
{
private static String XMLSchemaURI = "http://www.w3.org/2001/XMLSchema";
/**
* Constructor for XSDDOMHelper.
*/
public XSDDOMHelper()
{
super();
}
public Node getChildNode(Element parent, String childName)
{
/* NodeList nodeList = parent.getElementsByTagNameNS(XMLSchemaURI, childName);
if (nodeList.getLength() > 0)
return nodeList.item(0);
return null;
*/
NodeList list = null;
if (parent != null)
{
list = parent.getChildNodes();
}
if (list != null)
{
// Performance issue perhaps?
for (int i = 0; i < list.getLength(); i++)
{
if (list.item(i) instanceof Element)
{
if (list.item(i).getLocalName().equals(childName))
{
return list.item(i);
}
}
}
}
return null;
}
public void changeDerivedByType(Element element, String derivedByType, String type)
{
Document doc = element.getOwnerDocument();
String prefix = element.getPrefix();
prefix = prefix == null ? "" : prefix + ":";
Element derivedByElement = getDerivedByElement(element);
if (derivedByElement != null && derivedByElement.getLocalName().equals(derivedByType))
{
return; // it's already the derived by type
}
Element newNode;
if (derivedByType.equals("restriction"))
{
newNode = doc.createElementNS(XSDDOMHelper.XMLSchemaURI, prefix + XSDConstants.RESTRICTION_ELEMENT_TAG);
}
else
{
newNode = doc.createElementNS(XSDDOMHelper.XMLSchemaURI, prefix + XSDConstants.EXTENSION_ELEMENT_TAG);
}
newNode.setAttribute("base", type);
if (derivedByElement != null)
{
if (derivedByElement.hasChildNodes())
{
NodeList nodes = derivedByElement.getChildNodes();
// use clones so we don't have a refresh problem
for (int i = 0; i < nodes.getLength(); i++)
{
Node node = nodes.item(i);
newNode.appendChild(node.cloneNode(true));
}
}
element.replaceChild(newNode, derivedByElement);
}
else
{
Element parent = (Element) element.getParentNode(); // get back to complexType
NodeList nodes = parent.getChildNodes();
ArrayList nodeSaveList = new ArrayList();
// save children. (nodes turns out to be the same object as parent;
// deleting them from parent will delete them from nodes.)
for (int i = 0; i < nodes.getLength(); i++)
{
Node node = nodes.item(i);
nodeSaveList.add(node);
}
// remove children so we can surround them by complexContent
for (int i = 0; i < nodeSaveList.size(); i++)
{
Node node = (Node) nodeSaveList.get(i);
parent.removeChild(node);
}
// build a complexContent element
Element complexContent = doc.createElementNS(XSDDOMHelper.XMLSchemaURI, prefix + XSDConstants.COMPLEXCONTENT_ELEMENT_TAG);
parent.appendChild(complexContent); // insert into complexType
complexContent.appendChild(newNode); // insert derivation type
for (int i = 0; i < nodeSaveList.size(); i++) // insert children previously of complexType
{
Node node = (Node) nodeSaveList.get(i);
newNode.appendChild(node.cloneNode(true));
}
parent.appendChild(complexContent);
formatChild(complexContent);
}
}
/**
* Get the derived by node given the complexContent or simpleContent node
*/
public Element getDerivedByElement(Element element)
{
Node restrictionChild = getChildNode(element, "restriction");
Node extensionChild = getChildNode(element, "extension");
if (restrictionChild != null)
{
if (restrictionChild instanceof Element)
{
return (Element)restrictionChild;
}
}
if (extensionChild != null)
{
if (extensionChild instanceof Element)
{
return (Element)extensionChild;
}
}
return null;
}
public Element getDerivedByElementFromSimpleType(Element element)
{
Node atomic = getChildNode(element, "restriction");
Node list = getChildNode(element, "list");
Node union = getChildNode(element, "union");
if (atomic instanceof Element)
{
return (Element)atomic;
}
if (list instanceof Element)
{
return (Element)list;
}
if (union instanceof Element)
{
return (Element)union;
}
return null;
}
/**
* Get the derived by node given the ComplexType node
* Returns the first one, if say, the INVALID schema has more than one
*/
public Element getDerivedByElementFromComplexType(Element element)
{
NodeList nl = element.getChildNodes();
int j = 0;
for (j = 0; j < nl.getLength(); j++)
{
Node aNode = nl.item(j);
if (inputEquals(aNode, XSDConstants.COMPLEXCONTENT_ELEMENT_TAG, false))
{
break;
}
else if (inputEquals(aNode, XSDConstants.SIMPLECONTENT_ELEMENT_TAG, false))
{
break;
}
}
Element derivedByNode = getDerivedByElement((Element)nl.item(j));
return derivedByNode;
}
/**
* Get the content model given the ComplexType node
* Returns the first one, if say, the INVALID schema has more than one
*/
public Element getContentModelFromParent(Element element)
{
NodeList nl = element.getChildNodes();
int j = 0;
boolean modelExists = false;
int length = nl.getLength();
for (j = 0; j < length; j++)
{
Node aNode = nl.item(j);
if (inputEquals(aNode, XSDConstants.COMPLEXCONTENT_ELEMENT_TAG, false))
{
modelExists = true;
break;
}
else if (inputEquals(aNode, XSDConstants.SIMPLECONTENT_ELEMENT_TAG, false))
{
modelExists = true;
break;
}
else if (inputEquals(aNode, XSDConstants.SEQUENCE_ELEMENT_TAG, false))
{
modelExists = true;
break;
}
else if (inputEquals(aNode, XSDConstants.CHOICE_ELEMENT_TAG, false))
{
modelExists = true;
break;
}
else if (inputEquals(aNode, XSDConstants.ALL_ELEMENT_TAG, false))
{
modelExists = true;
break;
}
}
if (!modelExists)
{
return null;
}
Element derivedByNode = (Element)nl.item(j);
return derivedByNode;
}
/**
*
*/
public void changeContentModel(Element complexTypeElement, String contentModel, Element sequenceChoiceOrAllElement)
{
Document doc = complexTypeElement.getOwnerDocument();
String prefix = complexTypeElement.getPrefix();
prefix = prefix == null ? "" : prefix + ":";
Element contentModelElement = getContentModelFromParent(complexTypeElement);
if (contentModelElement.getLocalName().equals(contentModel))
{
return; // it's already the content model
}
Element newNode;
newNode = doc.createElementNS(XSDDOMHelper.XMLSchemaURI, prefix + contentModel);
if (contentModelElement.hasChildNodes())
{
NodeList nodes = contentModelElement.getChildNodes();
// use clones so we don't have a refresh problem
for (int i = 0; i < nodes.getLength(); i++)
{
Node node = nodes.item(i);
if (node instanceof Element)
{
if (node.getLocalName().equals(XSDConstants.ANNOTATION_ELEMENT_TAG))
{
if (!(XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.SEQUENCE_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.CHOICE_ELEMENT_TAG, false) ||
XSDDOMHelper.inputEquals(contentModelElement, XSDConstants.ALL_ELEMENT_TAG, false)))
{
newNode.appendChild(node.cloneNode(true));
}
}
else if (node.getLocalName().equals(XSDConstants.RESTRICTION_ELEMENT_TAG) ||
node.getLocalName().equals(XSDConstants.EXTENSION_ELEMENT_TAG))
{
newNode.appendChild(node.cloneNode(true));
if (sequenceChoiceOrAllElement != null)
{
node.appendChild(sequenceChoiceOrAllElement);
}
}
else
{
removeNodeAndWhitespace(node);
}
}
else
{
newNode.appendChild(node.cloneNode(true));
}
}
}
complexTypeElement.replaceChild(newNode, contentModelElement);
}
public Element cloneElement(Element parent, Element sourceNode)
{
Document doc = parent.getOwnerDocument();
String prefix = parent.getPrefix();
prefix = prefix == null ? "" : prefix + ":";
Element newNode = doc.createElementNS(XSDDOMHelper.XMLSchemaURI, prefix + sourceNode.getLocalName());
if (sourceNode.hasChildNodes())
{
NodeList nodes = sourceNode.getChildNodes();
// use clones so we don't have a refresh problem
for (int i = 0; i < nodes.getLength(); i++)
{
Node node = nodes.item(i);
newNode.appendChild(node.cloneNode(true));
}
}
return newNode;
// parent.replaceChild(newNode, sourceNode);
}
public static boolean hasOnlyWhitespace(Node node)
{
NodeList list = node.getChildNodes();
int length = list.getLength();
boolean hasOnlyWhitespace = true;
for (int i = 0; i < length; i++)
{
Node child = list.item(i);
if (child.getNodeType() != Node.TEXT_NODE)
{
hasOnlyWhitespace = false;
break;
}
else
{
String value = child.getNodeValue();
String trimmedValue = value.trim();
if (trimmedValue.length() != 0)
{
hasOnlyWhitespace = false;
}
}
}
return hasOnlyWhitespace;
}
public static void removeNodeAndWhitespace(Node node)
{
Node parentNode = node.getParentNode();
Node nextElement = getNextElementNode(node);
Node previousElement = getPreviousElementNode(node);
Node nextSibling = node.getNextSibling();
if (nextSibling instanceof Text)
{
parentNode.removeChild(nextSibling);
}
if (parentNode != null)
{
parentNode.removeChild(node);
}
if (nextElement != null)
{
formatChild(nextElement);
}
if (previousElement != null)
{
formatChild(previousElement);
}
}
public static void formatChild(Node child)
{
if (child instanceof IDOMNode)
{
IDOMModel model = ((IDOMNode)child).getModel();
try
{
// tell the model that we are about to make a big model change
model.aboutToChangeModel();
IStructuredFormatProcessor formatProcessor = new FormatProcessorXML();
formatProcessor.formatNode(child);
}
finally
{
// tell the model that we are done with the big model change
model.changedModel();
}
}
}
private static Node getNextElementNode(Node node)
{
Node next = node.getNextSibling();
while (!(next instanceof Element) && next != null)
{
next = next.getNextSibling();
}
if (next instanceof Text)
{
return null;
}
return next;
}
private static Node getPreviousElementNode(Node node)
{
Node previous = node.getPreviousSibling();
while (!(previous instanceof Element) && previous != null)
{
previous = previous.getPreviousSibling();
}
if (previous instanceof Text)
{
return null;
}
return previous;
}
// issue (cs) what's this method supposed to do?
// bizzare name
public static boolean inputEquals(Object input, String tagname, boolean isRef)
{
if (input instanceof Element)
{
Element element = (Element) input;
if (element.getLocalName().equals(tagname))
{
boolean refPresent = element.hasAttribute("ref");
return refPresent == isRef;
}
}
return false;
}
}