/******************************************************************************* * 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; } }