blob: 9427285e4fc40a6ccd4b8f94f997011e582914e1 [file] [log] [blame]
/*
* Copyright 2001-2004 The Apache Software Foundation.
// (c) Copyright IBM Corp. 2004, 2005 All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.wsdl.symbolTable;
import org.apache.axis.Constants;
import org.apache.axis.utils.JavaUtils;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.namespace.QName;
import javax.xml.rpc.holders.BooleanHolder;
import javax.xml.rpc.holders.IntHolder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
/**
* This class contains static utility methods specifically for schema type queries.
*
* @author Rich Scheuerle (scheu@us.ibm.com)
*/
public class CSchemaUtils extends SchemaUtils
{
/** Field VALUE_QNAME */
static final QName VALUE_QNAME = Utils.findQName("", "value");
/**
* This method checks mixed=true attribute is set either on
* complexType or complexContent element.
*/
public static boolean isMixed(Node node)
{
// Expecting a schema complexType
if (isXSDNode(node, "complexType"))
{
String mixed = ((Element) node).getAttribute("mixed");
if (mixed != null && mixed.length() > 0)
{
return ("true".equalsIgnoreCase(mixed) || "1".equals(mixed));
}
// Under the complexType there could be complexContent with
// mixed="true"
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexContent"))
{
mixed = ((Element) kid).getAttribute("mixed");
return ("true".equalsIgnoreCase(mixed) || "1".equals(mixed));
}
}
}
return false;
}
public static Node getUnionNode(Node node)
{
// Expecting a schema complexType
if (isXSDNode(node, "simpleType"))
{
// Under the simpleType there could be union
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "union"))
return kid;
}
}
return null;
}
public static Node getListNode(Node node)
{
// Expecting a schema simpleType
if (isXSDNode(node, "simpleType"))
{
// Under the simpleType there could be list
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "list"))
return kid;
}
}
return null;
}
public static boolean isSimpleTypeWithUnion(Node node)
{
return (getUnionNode(node) != null);
}
/**
* This method checks out if the given node satisfies the 3rd condition
* of the "wrapper" style:
* such an element (a wrapper) must be of a complex type defined using the
* xsd:sequence compositor and containing only elements declarations.
* (excerpt from JAX-RPC spec 1.1 Maintenanace Review 2 Chapter 6 Section 4.1.)
*
* @param node
* @return
*/
public static boolean isWrappedType(Node node)
{
if (node == null)
return false;
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
boolean hasComplexType = false;
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexType"))
{
node = kid;
hasComplexType = true;
break;
}
}
if (!hasComplexType)
return false;
}
// Expecting a schema complexType
if (isXSDNode(node, "complexType"))
{
// Under the complexType there could be complexContent/simpleContent
// and extension elements if this is a derived type.
// A wrapper element must be complex-typed.
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexContent"))
return false;
else if (isXSDNode(kid, "simpleContent"))
return false;
}
// Under the complexType there may be choice, sequence, group and/or all nodes.
// (There may be other #text nodes, which we will ignore).
// The complex type of a wrapper element must have only sequence
// and again element declarations in the sequence.
children = node.getChildNodes();
int len = children.getLength();
for (int j = 0; j < len; j++)
{
Node kid = children.item(j);
String localName = kid.getLocalName();
if (localName != null && Constants.isSchemaXSD(kid.getNamespaceURI()))
{
if (localName.equals("sequence"))
{
Node sequenceNode = kid;
NodeList sequenceChildren = sequenceNode.getChildNodes();
int sequenceLen = sequenceChildren.getLength();
for (int k = 0; k < sequenceLen; k++)
{
Node sequenceKid = sequenceChildren.item(k);
String sequenceLocalName = sequenceKid.getLocalName();
if (sequenceLocalName != null &&
Constants.isSchemaXSD(sequenceKid.getNamespaceURI()))
{
// allow choice with element children
if (sequenceLocalName.equals("choice"))
{
Node choiceNode = sequenceKid;
NodeList choiceChildren = choiceNode.getChildNodes();
int choiceLen = choiceChildren.getLength();
for (int l = 0; l < choiceLen; l++)
{
Node choiceKid = choiceChildren.item(l);
String choiceLocalName = choiceKid.getLocalName();
if (choiceLocalName != null &&
Constants.isSchemaXSD(choiceKid.getNamespaceURI()))
{
if (!choiceLocalName.equals("element"))
return false;
}
}
}
else if (!sequenceLocalName.equals("element"))
return false;
}
}
return true;
}
else
return false;
}
}
}
// allows void type
return true;
}
/**
* If the specified node represents a supported JAX-RPC complexType or
* simpleType, a Vector is returned which contains ElementDecls for the
* child element names.
* If the element is a simpleType, an ElementDecls is built representing
* the restricted type with the special name "value".
* If the element is a complexType which has simpleContent, an ElementDecl
* is built representing the extended type with the special name "value".
* This method does not return attribute names and types
* (use the getContainedAttributeTypes)
* If the specified node is not a supported
* JAX-RPC complexType/simpleType/element null is returned.
*
* @param node
* @param symbolTable
* @return
*/
public static Vector getContainedElementDeclarations(Node node,
SymbolTable symbolTable) {
if (node == null)
return null;
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexType"))
{
node = kid;
break;
}
}
}
// Expecting a schema complexType or simpleType
if (isXSDNode(node, "complexType"))
{
// Under the complexType there could be complexContent/simpleContent
// and extension elements if this is a derived type. Skip over these.
NodeList children = node.getChildNodes();
Node complexContent = null;
Node simpleContent = null;
Node extension = null;
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexContent"))
{
complexContent = kid;
break; // REMIND: should this be here or on either branch?
}
else if (isXSDNode(kid, "simpleContent"))
simpleContent = kid;
}
if (complexContent != null)
{
children = complexContent.getChildNodes();
for (int j = 0; (j < children.getLength()) && (extension == null); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "extension") || isXSDNode(kid, "restriction"))
extension = kid;
}
}
if (simpleContent != null)
{
children = simpleContent.getChildNodes();
int len = children.getLength();
for (int j = 0; (j < len) && (extension == null); j++)
{
Node kid = children.item(j);
String localName = kid.getLocalName();
if ((localName != null)
&& (localName.equals("extension") || localName.equals("restriction"))
&& Constants.isSchemaXSD(kid.getNamespaceURI()))
{
// get the type of the extension/restriction from the "base" attribute
QName extendsOrRestrictsTypeName =
Utils.getTypeQName(children.item(j), new BooleanHolder(), false);
TypeEntry extendsOrRestrictsType =
symbolTable.getTypeEntry(extendsOrRestrictsTypeName, false);
// If this type extends a simple type, then add the
// special "value" ElementDecl, else this type is
// extending another simpleContent type and will
// already have a "value".
if (extendsOrRestrictsType == null || extendsOrRestrictsType.isBaseType())
{
// Return an element declaration with a fixed name
// ("value") and the correct type.
Vector v = new Vector();
CElementDecl elem = new CElementDecl(extendsOrRestrictsType, VALUE_QNAME);
v.add(elem);
return v;
}
else
{
// There can't be any other elements in a
// simpleContent node.
return null;
}
}
}
}
if (extension != null)
node = extension; // Skip over complexContent and extension
// Under the complexType there may be choice, sequence, group and/or all nodes.
// (There may be other #text nodes, which we will ignore).
children = node.getChildNodes();
Vector v = new Vector();
int len = children.getLength();
for (int j = 0; j < len; j++)
{
Node kid = children.item(j);
String localName = kid.getLocalName();
if (localName != null && Constants.isSchemaXSD(kid.getNamespaceURI()))
{
if (localName.equals("sequence"))
v.addAll(processSequenceNode(kid, symbolTable));
else if (localName.equals("all"))
v.addAll(processAllNode(kid, symbolTable));
else if (localName.equals("choice"))
v.addAll(processChoiceNode(kid, symbolTable));
else if (localName.equals("group"))
v.addAll(processGroupNode(kid, symbolTable));
}
}
return v;
}
else if (isXSDNode(node, "group"))
{
/*
* Does this else clause make any sense anymore if
* we're treating refs to xs:groups like a macro inclusion
* into the referencing type?
* Maybe this else clause should never be possible?
*
NodeList children = node.getChildNodes();
Vector v = new Vector();
int len = children.getLength();
for (int j = 0; j < len; j++) {
Node kid = children.item(j);
String localName = kid.getLocalName();
if (localName != null &&
Constants.isSchemaXSD(kid.getNamespaceURI())) {
if (localName.equals("sequence")) {
v.addAll(processSequenceNode(kid, symbolTable));
} else if (localName.equals("all")) {
v.addAll(processAllNode(kid, symbolTable));
} else if (localName.equals("choice")) {
v.addAll(processChoiceNode(kid, symbolTable));
}
}
}
return v;
*/
return null;
}
else
{
// This may be a simpleType, return the type with the name "value"
QName[] simpleQName = getContainedSimpleTypes(node);
if (simpleQName != null)
{
Vector v = null;
for (int i = 0; i < simpleQName.length; i++)
{
TypeEntry simpleType = symbolTable.getType(simpleQName[i]);
if (simpleType != null)
{
if (v == null)
v = new Vector();
QName qname = null;
if (simpleQName.length > 1)
qname = new QName("", simpleQName[i].getLocalPart() + "Value");
else
qname = new QName("", "value");
v.add(new CElementDecl(simpleType, qname));
}
}
return v;
}
}
return null;
}
/**
* Invoked by getContainedElementDeclarations to get the child element types
* and child element names underneath a Choice Node
*
* @param choiceNode
* @param symbolTable
* @return
*/
private static Vector processChoiceNode(Node choiceNode, SymbolTable symbolTable)
{
Vector v = new Vector();
NodeList children = choiceNode.getChildNodes();
int len = children.getLength();
for (int j = 0; j < len; j++)
{
Node kid = children.item(j);
String localName = kid.getLocalName();
if (localName != null && Constants.isSchemaXSD(kid.getNamespaceURI()))
{
if (localName.equals("choice"))
v.addAll(processChoiceNode(kid, symbolTable));
else if (localName.equals("sequence"))
v.addAll(processSequenceNode(kid, symbolTable));
else if (localName.equals("group"))
v.addAll(processGroupNode(kid, symbolTable));
else if (localName.equals("element"))
{
CElementDecl elem = processChildElementNode(kid, symbolTable);
if (elem != null)
{
elem.setChoiceElement(true);
v.add(elem);
}
}
else if (localName.equals("any"))
{
// Represent this as an element named any of type any type.
// This will cause it to be serialized with the element
// serializer.
TypeEntry type = symbolTable.getType(Constants.XSD_ANY);
CElementDecl elem = new CElementDecl(type, Utils.findQName("", "any"));
elem.setAnyElement(true);
v.add(elem);
}
}
}
return v;
}
/**
* Returns named child node.
*
* @param parentNode Parent node.
* @param name Element name of child node to return.
*/
private static Node getChildByName(Node parentNode, String name) throws DOMException
{
if (parentNode == null)
return null;
NodeList children = parentNode.getChildNodes();
if (children != null)
{
for (int i = 0; i < children.getLength(); i++)
{
Node child = children.item(i);
if (child != null)
{
if ((child.getNodeName() != null && (name.equals(child.getNodeName()))) ||
(child.getLocalName() != null && (name.equals(child.getLocalName()))))
return child;
}
}
}
return null;
}
/**
* Returns all textual nodes of a subnode defined by a parent node
* and a path of element names to that subnode.
*
* @param root Parent node.
* @param path Path of element names to text of interest, delimited by "/".
*/
public static String getTextByPath(Node root, String path) throws DOMException
{
StringTokenizer st = new StringTokenizer(path, "/");
Node node = root;
while (st.hasMoreTokens())
{
String elementName = st.nextToken();
Node child = getChildByName(node, elementName);
if (child == null)
throw new DOMException(DOMException.NOT_FOUND_ERR, "could not find " + elementName);
node = child;
}
// should have found the node
String text = "";
NodeList children = node.getChildNodes();
if (children != null)
{
for (int i = 0; i < children.getLength(); i++)
{
Node child = children.item(i);
if (child != null)
{
if (child.getNodeName() != null
&& (child.getNodeName().equals("#text")
|| child.getNodeName().equals("#cdata-section")))
{
text += child.getNodeValue();
}
}
}
}
return text;
}
/**
* Returns the complete text of the child xsd:annotation/xsd:documentation
* element from the provided node. Only the first annotation element and
* the first documentation element in the annotation element will be used.
*
* @param typeNode Parent node.
*/
public static String getAnnotationDocumentation(Node typeNode)
{
Node annotationNode = typeNode.getFirstChild();
while (annotationNode != null)
{
if (isXSDNode(annotationNode, "annotation"))
break;
annotationNode = annotationNode.getNextSibling();
}
Node documentationNode;
if (annotationNode != null)
{
documentationNode = annotationNode.getFirstChild();
while (documentationNode != null)
{
if (isXSDNode(documentationNode, "documentation"))
break;
documentationNode = documentationNode.getNextSibling();
}
}
else
documentationNode = null;
// should have found the node if it exists
String text = "";
if (documentationNode != null)
{
NodeList children = documentationNode.getChildNodes();
if (children != null)
{
for (int i = 0; i < children.getLength(); i++)
{
Node child = children.item(i);
if (child != null)
{
if (child.getNodeName() != null
&& (child.getNodeName().equals("#text")
|| child.getNodeName().equals("#cdata-section")))
{
text += child.getNodeValue();
}
}
}
}
}
return text;
}
/**
* Invoked by getContainedElementDeclarations to get the child element types
* and child element names underneath a Sequence Node
*
* @param sequenceNode
* @param symbolTable
* @return
*/
private static Vector processSequenceNode(Node sequenceNode,
SymbolTable symbolTable)
{
Vector v = new Vector();
NodeList children = sequenceNode.getChildNodes();
int len = children.getLength();
for (int j = 0; j < len; j++)
{
Node kid = children.item(j);
String localName = kid.getLocalName();
if (localName != null && Constants.isSchemaXSD(kid.getNamespaceURI()))
{
if (localName.equals("choice"))
v.addAll(processChoiceNode(kid, symbolTable));
else if (localName.equals("sequence"))
v.addAll(processSequenceNode(kid, symbolTable));
else if (localName.equals("group"))
v.addAll(processGroupNode(kid, symbolTable));
else if (localName.equals("any"))
{
// Represent this as an element named any of type any type.
// This will cause it to be serialized with the element
// serializer.
TypeEntry type = symbolTable.getType(Constants.XSD_ANY);
CElementDecl elem = new CElementDecl(type, Utils.findQName("", "any"));
elem.setAnyElement(true);
v.add(elem);
}
else if (localName.equals("element"))
{
CElementDecl elem = processChildElementNode(kid, symbolTable);
if (elem != null)
v.add(elem);
}
}
}
return v;
}
/**
* Invoked by getContainedElementDeclarations to get the child element types
* and child element names underneath a group node. If a ref attribute is
* specified, only the referenced group element is returned.
*
* @param groupNode
* @param symbolTable
* @return
*/
private static Vector processGroupNode(Node groupNode, SymbolTable symbolTable)
{
Vector v = new Vector();
if (groupNode.getAttributes().getNamedItem("ref") == null)
{
NodeList children = groupNode.getChildNodes();
int len = children.getLength();
for (int j = 0; j < len; j++)
{
Node kid = children.item(j);
String localName = kid.getLocalName();
if (localName != null && Constants.isSchemaXSD(kid.getNamespaceURI()))
{
if (localName.equals("choice"))
v.addAll(processChoiceNode(kid, symbolTable));
else if (localName.equals("sequence"))
v.addAll(processSequenceNode(kid, symbolTable));
else if (localName.equals("all"))
v.addAll(processAllNode(kid, symbolTable));
}
}
}
else
{
QName nodeType = Utils.getTypeQName(groupNode, new BooleanHolder(), false);
// The value of the second argument is 'false' since global model group
// definitions are always represented by objects whose type is
// assignment compatible with 'org.apache.axis.wsdl.symbolTable.Type'.
TypeEntry type = symbolTable.getTypeEntry(nodeType, false);
if (type != null && type.getNode() != null)
{
Node node = type.getNode();
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
QName subNodeKind = Utils.getNodeQName(children.item(j));
if ((subNodeKind != null)
&& Constants.isSchemaXSD(subNodeKind.getNamespaceURI()))
{
if (subNodeKind.getLocalPart().equals("sequence"))
v.addAll(processSequenceNode(children.item(j), symbolTable));
else if (subNodeKind.getLocalPart().equals("all"))
v.addAll(processAllNode(children.item(j), symbolTable));
else if (subNodeKind.getLocalPart().equals("choice"))
v.addAll(processChoiceNode(children.item(j), symbolTable));
}
}
}
}
return v;
}
/**
* Invoked by getContainedElementDeclarations to get the child element types
* and child element names underneath an all node.
*
* @param allNode
* @param symbolTable
* @return
*/
private static Vector processAllNode(Node allNode, SymbolTable symbolTable)
{
Vector v = new Vector();
NodeList children = allNode.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "element"))
{
CElementDecl elem = processChildElementNode(kid, symbolTable);
if (elem != null)
{
elem.setAllElement(true);
v.add(elem);
}
}
}
return v;
}
/**
* Invoked by getContainedElementDeclarations to get the child element type
* and child element name for a child element node.
* <p/>
* If the specified node represents a supported JAX-RPC child element,
* we return an ElementDecl containing the child element name and type.
*
* @param elementNode
* @param symbolTable
* @return
*/
private static CElementDecl processChildElementNode(Node elementNode,
SymbolTable symbolTable)
{
// Get the name qnames.
QName nodeName = Utils.getNodeNameQName(elementNode);
BooleanHolder forElement = new BooleanHolder();
String comments = null;
comments = getAnnotationDocumentation(elementNode);
// The type qname is used to locate the TypeEntry, which is then
// used to retrieve the proper java name of the type.
QName nodeType = Utils.getTypeQName(elementNode, forElement, false);
TypeEntry type = symbolTable.getTypeEntry(nodeType, forElement.value);
// We want to treat schema references same way we treat anyType.
if (type == null
&& nodeType.getLocalPart().equals("schema")
&& nodeType.getNamespaceURI().equals("http://www.w3.org/2001/XMLSchema"))
{
forElement.value = false;
type = symbolTable.getTypeEntry(nodeType, forElement.value);
}
//The boolean field 'qualified' is set to true
//if the element is namespace qualified.
//The default value is unqualified.
boolean qualified = false;
// An element inside a complex type is either qualified or unqualified.
// If the ref= attribute is used, the name of the ref'd element is used
// (which must be a root element). If the ref= attribute is not
// used, the name of the element is unqualified.
if (!forElement.value)
{
// check the Form (or elementFormDefault) attribute of this node to
// determine if it should be namespace quailfied or not.
String form = Utils.getAttribute(elementNode, "form");
if ((form != null) && form.equals("unqualified"))
nodeName = Utils.findQName("", nodeName.getLocalPart());
else if ((form != null) && form.equals("qualified"))
qualified = true;
else if (form == null)
{
// check elementFormDefault on schema element
String def = Utils.getScopedAttribute(elementNode, "elementFormDefault");
if ((def == null) || def.equals("unqualified"))
nodeName = Utils.findQName("", nodeName.getLocalPart());
else if ((def == null) || def.equals("qualified"))
qualified = true;
}
}
if (type != null)
{
CElementDecl elem = new CElementDecl(type, nodeName);
elem.setDocumentation(comments);
String minOccurs = Utils.getAttribute(elementNode, "minOccurs");
if (minOccurs != null) {
elem.setMinOccurs(Integer.parseInt(minOccurs));
}
String maxOccurs = Utils.getAttribute(elementNode, "maxOccurs");
if (maxOccurs != null) {
if (maxOccurs.equals("unbounded")) {
elem.setMaxOccurs(CElementDecl.UNBOUNDED);
}
else
elem.setMaxOccurs(Integer.parseInt(maxOccurs));
}
elem.setNillable(JavaUtils.isTrueExplicitly(Utils.getAttribute(elementNode, "nillable")));
String useValue = Utils.getAttribute(elementNode, "use");
if (useValue != null)
elem.setOptional(useValue.equalsIgnoreCase("optional"));
elem.setNsQualified(qualified);
return elem;
}
return null;
}
/**
* Returns the WSDL2Java QName for the anonymous type of the element
* or null.
*
* @param node
* @return
*/
public static QName getElementAnonQName(Node node)
{
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexType") || isXSDNode(kid, "simpleType"))
return Utils.getNodeNameQName(kid);
}
}
return null;
}
/**
* Returns the WSDL2Java QName for the anonymous type of the attribute
* or null.
*
* @param node
* @return
*/
public static QName getAttributeAnonQName(Node node)
{
if (isXSDNode(node, "attribute"))
{
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexType") || isXSDNode(kid, "simpleType"))
return Utils.getNodeNameQName(kid);
}
}
return null;
}
/**
* If the specified node is a simple type or contains simpleContent, return true
*
* @param node
* @return
*/
public static boolean isSimpleTypeOrSimpleContent(Node node) {
if (node == null)
return false;
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexType"))
{
node = kid;
break;
}
else if (isXSDNode(kid, "simpleType"))
return true;
}
}
// Expecting a schema complexType or simpleType
if (isXSDNode(node, "simpleType"))
return true;
if (isXSDNode(node, "complexType"))
{
// Under the complexType there could be complexContent/simpleContent
// and extension elements if this is a derived type. Skip over these.
NodeList children = node.getChildNodes();
Node complexContent = null;
Node simpleContent = null;
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexContent"))
{
complexContent = kid;
break;
}
else if (isXSDNode(kid, "simpleContent"))
simpleContent = kid;
}
if (complexContent != null)
return false;
if (simpleContent != null)
return true;
}
return false;
}
/**
* Test whether <tt>node</tt> is not null, belongs to the XML
* Schema namespace, and has a localName that matches
* <tt>schemaLocalName</tt>
* <p/>
* This can be used to determine that a given Node defines a
* schema "complexType" "element" and so forth.
*
* @param node a <code>Node</code> value
* @param schemaLocalName a <code>String</code> value
* @return true if the node is matches the name in the schema namespace.
*/
private static boolean isXSDNode(Node node, String schemaLocalName)
{
if (node == null)
return false;
String localName = node.getLocalName();
if (localName == null)
return false;
return (localName.equals(schemaLocalName) &&
Constants.isSchemaXSD(node.getNamespaceURI()));
}
/**
* Look for the base type of node iff node is a complex type that has been
* derived by restriction; otherwise return null.
*
* @param node
* @param symbolTable
* @return
*/
public static TypeEntry getComplexElementRestrictionBase(Node node,
SymbolTable symbolTable)
{
if (node == null)
return null;
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
Node complexNode = null;
for (int j = 0; (j < children.getLength()) && (complexNode == null); j++)
{
if (isXSDNode(children.item(j), "complexType"))
{
complexNode = children.item(j);
node = complexNode;
}
}
}
// Expecting a schema complexType
if (isXSDNode(node, "complexType"))
{
// Under the complexType there could be should be a complexContent &
// restriction elements if this is a derived type.
NodeList children = node.getChildNodes();
Node content = null;
Node restriction = null;
for (int j = 0; (j < children.getLength()) && (content == null); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexContent") || isXSDNode(kid, "simpleContent"))
content = kid;
}
if (content != null)
{
children = content.getChildNodes();
for (int j = 0; (j < children.getLength()) && (restriction == null); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "restriction"))
restriction = kid;
}
}
if (restriction == null)
return null;
else
{
// Get the QName of the extension base
QName restrictionType =
Utils.getTypeQName(restriction, new BooleanHolder(), false);
if (restrictionType == null)
return null;
else
{
// Return associated Type
return symbolTable.getType(restrictionType);
}
}
}
else
return null;
}
/**
* If the specified node represents a supported JAX-RPC complexType/element
* which extends another complexType. The Type of the base is returned.
*
* @param node
* @param symbolTable
* @return
*/
public static TypeEntry getComplexElementExtensionBase(Node node,
SymbolTable symbolTable)
{
if (node == null)
return null;
TypeEntry cached = (TypeEntry) symbolTable.node2ExtensionBase.get(node);
if (cached != null)
return cached; // cache hit
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
Node complexNode = null;
for (int j = 0; (j < children.getLength()) && (complexNode == null); j++)
{
if (isXSDNode(children.item(j), "complexType"))
{
complexNode = children.item(j);
node = complexNode;
}
}
}
// Expecting a schema complexType
if (isXSDNode(node, "complexType"))
{
// Under the complexType there could be should be a complexContent &
// extension elements if this is a derived type.
NodeList children = node.getChildNodes();
Node content = null;
Node extension = null;
for (int j = 0; (j < children.getLength()) && (content == null); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexContent") || isXSDNode(kid, "simpleContent"))
content = kid;
}
if (content != null)
{
children = content.getChildNodes();
for (int j = 0; (j < children.getLength()) && (extension == null); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "extension"))
extension = kid;
}
}
if (extension == null)
cached = null;
else
{
// Get the QName of the extension base
QName extendsType =
Utils.getTypeQName(extension, new BooleanHolder(), false);
if (extendsType == null)
cached = null;
else
{
// Return associated Type
cached = symbolTable.getType(extendsType);
}
}
}
symbolTable.node2ExtensionBase.put(node, cached);
return cached;
}
/**
* If the specified node represents a 'normal' non-enumeration simpleType,
* the QName of the simpleType base is returned.
*
* @param node
* @return
*/
public static QName getSimpleTypeBase(Node node)
{
QName[] qname = getContainedSimpleTypes(node);
if ((qname != null) && (qname.length > 0))
return qname[0];
return null;
}
/**
* Method getContainedSimpleTypes
*
* @param node
* @return
*/
public static QName[] getContainedSimpleTypes(Node node)
{
QName[] baseQNames = null;
if (node == null)
return null;
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
if (isXSDNode(children.item(j), "simpleType"))
{
node = children.item(j);
break;
}
}
}
// Get the node kind, expecting a schema simpleType
if (isXSDNode(node, "simpleType"))
{
// Under the simpleType there should be a restriction.
// (There may be other #text nodes, which we will ignore).
NodeList children = node.getChildNodes();
Node restrictionNode = null;
Node unionNode = null;
for (int j = 0;
(j < children.getLength()) && (restrictionNode == null);
j++)
{
if (isXSDNode(children.item(j), "restriction"))
restrictionNode = children.item(j);
else if (isXSDNode(children.item(j), "union"))
unionNode = children.item(j);
}
// The restriction node indicates the type being restricted
// (the base attribute contains this type).
if (restrictionNode != null)
{
baseQNames = new QName[1];
baseQNames[0] =
Utils.getTypeQName(restrictionNode, new BooleanHolder(), false);
}
if (unionNode != null)
baseQNames = Utils.getMemberTypeQNames(unionNode);
// Look for enumeration elements underneath the restriction node
if ((baseQNames != null) && (restrictionNode != null) && (unionNode != null))
{
NodeList enums = restrictionNode.getChildNodes();
for (int i = 0; i < enums.getLength(); i++)
{
if (isXSDNode(enums.item(i), "enumeration"))
{
// Found an enumeration, this isn't a
// 'normal' simple type.
return null;
}
}
}
}
return baseQNames;
}
/**
* Returns the contained restriction or extension node underneath
* the specified node. Returns null if not found
*
* @param node
* @return
*/
public static Node getRestrictionOrExtensionNode(Node node)
{
Node re = null;
if (node == null)
return re;
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node n = children.item(j);
if (isXSDNode(n, "simpleType") || isXSDNode(n, "complexType")
|| isXSDNode(n, "simpleContent"))
{
node = n;
break;
}
}
}
// Get the node kind, expecting a schema simpleType
if (isXSDNode(node, "simpleType") || isXSDNode(node, "complexType"))
{
// Under the complexType there could be a complexContent.
NodeList children = node.getChildNodes();
Node complexContent = null;
if (node.getLocalName().equals("complexType"))
{
for (int j = 0; (j < children.getLength()) && (complexContent == null); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexContent") || isXSDNode(kid, "simpleContent"))
complexContent = kid;
}
node = complexContent;
}
// Now get the extension or restriction node
if (node != null)
{
children = node.getChildNodes();
for (int j = 0;(j < children.getLength()) && (re == null); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "extension") || isXSDNode(kid, "restriction"))
re = kid;
}
}
}
return re;
}
/**
* If the specified node represents an array encoding of one of the following
* forms, then return the qname repesenting the element type of the array.
*
* @param node is the node
* @param dims is the output value that contains the number of dimensions if return is not null
* @param itemQName will end up containing the "inner" QName for a
* wrapped literal array
* @return QName or null
*/
public static QName getArrayComponentQName(Node node,
IntHolder dims,
SymbolTable symbolTable)
{
dims.value = 1; // assume 1 dimension
QName qName = getCollectionComponentQName(node);
if (qName == null)
qName = getArrayComponentQName_JAXRPC(node, dims, symbolTable);
return qName;
}
/**
* If the specified node represents an element that references a collection
* then return the qname repesenting the component of the collection.
* <p/>
* <xsd:element name="alias" type="xsd:string" maxOccurs="unbounded"/>
* returns qname for"xsd:string"
* <p/>
* <xsd:complexType>
* <xsd:sequence>
* <xsd:element name="alias" type="xsd:string" maxOccurs="unbounded"/>
* </xsd:sequence>
* </xsd:complexType>
* returns qname for"xsd:string"
* <p/>
* <xsd:element ref="alias" maxOccurs="unbounded"/>
* returns qname for "alias"
*
* @param node is the Node
* @return QName of the compoent of the collection
*/
public static QName getCollectionComponentQName(Node node)
{
if (node == null)
return null;
// If the node kind is an element, dive get its type.
if (isXSDNode(node, "element"))
{
// Compare the componentQName with the name of the
// full name. If different, return componentQName
BooleanHolder forElement = new BooleanHolder();
QName componentQName = Utils.getTypeQName(node, forElement, true);
if (componentQName != null)
{
QName fullQName = Utils.getTypeQName(node, forElement, false);
if (!componentQName.equals(fullQName))
return componentQName;
}
}
return null;
}
/**
* If the specified node represents an array encoding of one of the following
* forms, then return the qname repesenting the element type of the array.
*
* @param node is the node
* @param dims is the output value that contains the number of dimensions if return is not null
* @return QName or null
* <p/>
* JAX-RPC Style 2:
* <xsd:complexType name="hobbyArray">
* <xsd:complexContent>
* <xsd:restriction base="soapenc:Array">
* <xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
* </xsd:restriction>
* </xsd:complexContent>
* </xsd:complexType>
* <p/>
* JAX-RPC Style 3:
* <xsd:complexType name="petArray">
* <xsd:complexContent>
* <xsd:restriction base="soapenc:Array">
* <xsd:sequence>
* <xsd:element name="alias" type="xsd:string" maxOccurs="unbounded"/>
* </xsd:sequence>
* </xsd:restriction>
* </xsd:complexContent>
* </xsd:complexType>
*/
private static QName getArrayComponentQName_JAXRPC(Node node,
IntHolder dims,
SymbolTable symbolTable)
{
dims.value = 0; // Assume 0
if (node == null)
return null;
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexType"))
{
node = kid;
break;
}
}
}
// Get the node kind, expecting a schema complexType
if (isXSDNode(node, "complexType"))
{
// Under the complexType there should be a complexContent.
// (There may be other #text nodes, which we will ignore).
NodeList children = node.getChildNodes();
Node complexContentNode = null;
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexContent") || isXSDNode(kid, "simpleContent"))
{
complexContentNode = kid;
break;
}
}
// Under the complexContent there should be a restriction.
// (There may be other #text nodes, which we will ignore).
Node restrictionNode = null;
if (complexContentNode != null)
{
children = complexContentNode.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "restriction"))
{
restrictionNode = kid;
break;
}
}
}
// The restriction node must have a base of soapenc:Array.
QName baseType = null;
if (restrictionNode != null)
{
baseType = Utils.getTypeQName(restrictionNode, new BooleanHolder(), false);
if (baseType != null)
{
if (!baseType.getLocalPart().equals("Array") ||
!Constants.isSOAP_ENC(baseType.getNamespaceURI()))
{
if (!symbolTable.arrayTypeQNames.contains(baseType))
baseType = null; // Did not find base=soapenc:Array
}
}
}
// Under the restriction there should be an attribute OR a sequence/all group node.
// (There may be other #text nodes, which we will ignore).
Node groupNode = null;
Node attributeNode = null;
if (baseType != null)
{
children = restrictionNode.getChildNodes();
for (int j = 0; (j < children.getLength())
&& (groupNode == null)
&& (attributeNode == null); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "sequence") || isXSDNode(kid, "all"))
{
groupNode = kid;
if (groupNode.getChildNodes().getLength() == 0)
{
// This covers the rather odd but legal empty sequence.
// <complexType name="ArrayOfString">
// <complexContent>
// <restriction base="soapenc:Array">
// <sequence/>
// <attribute ref="soapenc:arrayType" wsdl:arrayType="string[]"/>
// </restriction>
// </complexContent>
// </complexType>
groupNode = null;
}
}
if (isXSDNode(kid, "attribute"))
{
// If the attribute node does not have ref="soapenc:arrayType"
// then keep looking.
BooleanHolder isRef = new BooleanHolder();
QName refQName = Utils.getTypeQName(kid, isRef, false);
if ((refQName != null) && isRef.value
&& refQName.getLocalPart().equals("arrayType")
&& Constants.isSOAP_ENC(refQName.getNamespaceURI()))
attributeNode = kid;
}
}
}
// If there is an attribute node, look at wsdl:arrayType to get the element type
if (attributeNode != null)
{
String wsdlArrayTypeValue = null;
Vector attrs = Utils.getAttributesWithLocalName(attributeNode, "arrayType");
for (int i = 0;
(i < attrs.size()) && (wsdlArrayTypeValue == null);
i++)
{
Node attrNode = (Node) attrs.elementAt(i);
String attrName = attrNode.getNodeName();
QName attrQName = Utils.getQNameFromPrefixedName(attributeNode, attrName);
if (Constants.isWSDL(attrQName.getNamespaceURI()))
wsdlArrayTypeValue = attrNode.getNodeValue();
}
// The value could have any number of [] or [,] on the end
// Strip these off to get the prefixed name.
// The convert the prefixed name into a qname.
// Count the number of [ and , to get the dim information.
if (wsdlArrayTypeValue != null)
{
int i = wsdlArrayTypeValue.indexOf('[');
if (i > 0)
{
String prefixedName = wsdlArrayTypeValue.substring(0, i);
String mangledString = wsdlArrayTypeValue.replace(',', '[');
dims.value = 0;
int index = mangledString.indexOf('[');
while (index > 0)
{
dims.value++;
index = mangledString.indexOf('[', index + 1);
}
return Utils.getQNameFromPrefixedName(restrictionNode, prefixedName);
}
}
}
else if (groupNode != null)
{
// Get the first element node under the group node.
NodeList elements = groupNode.getChildNodes();
Node elementNode = null;
for (int i = 0; (i < elements.getLength()) && (elementNode == null); i++)
{
Node kid = elements.item(i);
if (isXSDNode(kid, "element"))
{
elementNode = elements.item(i);
break;
}
}
// The element node should have maxOccurs="unbounded" and
// a type
if (elementNode != null)
{
String maxOccursValue = Utils.getAttribute(elementNode, "maxOccurs");
if ((maxOccursValue != null) && maxOccursValue.equalsIgnoreCase("unbounded"))
{
// Get the QName of the type without considering maxOccurs
dims.value = 1;
return Utils.getTypeQName(elementNode, new BooleanHolder(), true);
}
}
}
}
return null;
}
/**
* adds an attribute node's type and name to the vector
* helper used by getContainedAttributeTypes
*
* @param v
* @param child
* @param symbolTable
*/
private static void addAttributeToVector(Vector v, Node child,
SymbolTable symbolTable)
{
// Get the name and type qnames.
// The type qname is used to locate the TypeEntry, which is then
// used to retrieve the proper java name of the type.
QName attributeName = Utils.getNodeNameQName(child);
BooleanHolder forElement = new BooleanHolder();
QName attributeType = Utils.getTypeQName(child, forElement, false);
// An attribute is either qualified or unqualified.
// If the ref= attribute is used, the name of the ref'd element is used
// (which must be a root element). If the ref= attribute is not
// used, the name of the attribute is unqualified.
if (!forElement.value)
{
// check the Form (or attributeFormDefault) attribute of
// this node to determine if it should be namespace
// quailfied or not.
String form = Utils.getAttribute(child, "form");
if ((form != null) && form.equals("unqualified"))
{
// Unqualified nodeName
attributeName = Utils.findQName("", attributeName.getLocalPart());
}
else if (form == null)
{
// check attributeFormDefault on schema element
String def = Utils.getScopedAttribute(child, "attributeFormDefault");
if ((def == null) || def.equals("unqualified"))
attributeName = Utils.findQName("", attributeName.getLocalPart());
}
}
else
attributeName = attributeType;
// Get the corresponding TypeEntry from the symbol table
TypeEntry type = symbolTable.getTypeEntry(attributeType, forElement.value);
// Try to get the corresponding global attribute ElementEntry
// from the symbol table.
if (type instanceof org.apache.axis.wsdl.symbolTable.Element)
type = ((org.apache.axis.wsdl.symbolTable.Element) type).getRefType();
// add type and name to vector, skip it if we couldn't parse it
// XXX - this may need to be revisited.
if ((type != null) && (attributeName != null))
{
CContainedAttribute attr = new CContainedAttribute(type, attributeName);
String useValue = Utils.getAttribute(child, "use");
if (useValue != null)
attr.setOptional(useValue.equalsIgnoreCase("optional"));
String fixedValue = Utils.getAttribute(child, "fixed");
if (fixedValue != null)
attr.setFixedValue(fixedValue);
String defaultValue = Utils.getAttribute(child, "default");
if (defaultValue != null)
attr.setDefaultValue(defaultValue);
v.add(attr);
}
}
/**
* adds an attribute to the vector
* helper used by addAttributeGroupToVector
*
* @param v
* @param symbolTable
* @param type
* @param name
*/
private static void addAttributeToVector(Vector v, SymbolTable symbolTable,
QName type, QName name)
{
TypeEntry typeEnt = symbolTable.getTypeEntry(type, false);
if (typeEnt != null)
v.add(new CContainedAttribute(typeEnt, name));
}
/**
* adds each attribute group's attribute node to the vector
* helper used by getContainedAttributeTypes
*
* @param v
* @param attrGrpnode
* @param symbolTable
*/
private static void addAttributeGroupToVector(Vector v, Node attrGrpnode,
SymbolTable symbolTable)
{
// get the type of the attributeGroup
QName attributeGroupType = Utils.getTypeQName(attrGrpnode, new BooleanHolder(), false);
TypeEntry type = symbolTable.getTypeEntry(attributeGroupType, false);
if (type != null)
{
if (type.getNode() != null)
{
// for each attribute or attributeGroup defined in the attributeGroup...
NodeList children = type.getNode().getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "attribute"))
addAttributeToVector(v, kid, symbolTable);
else if (isXSDNode(kid, "attributeGroup"))
addAttributeGroupToVector(v, kid, symbolTable);
}
}
else if (type.isBaseType())
{
// soap/encoding is treated as a "known" schema
// so let's act like we know it
if (type.getQName().equals(Constants.SOAP_COMMON_ATTRS11))
{
// 1.1 commonAttributes contains two attributes
addAttributeToVector(v, symbolTable, Constants.XSD_ID,
new QName(Constants.URI_SOAP11_ENC, "id"));
addAttributeToVector(v, symbolTable, Constants.XSD_ANYURI,
new QName(Constants.URI_SOAP11_ENC, "href"));
}
else if (type.getQName().equals(Constants.SOAP_COMMON_ATTRS12))
{
// 1.2 commonAttributes contains one attribute
addAttributeToVector(v, symbolTable, Constants.XSD_ID,
new QName(Constants.URI_SOAP12_ENC, "id"));
}
else if (type.getQName().equals(Constants.SOAP_ARRAY_ATTRS11))
{
// 1.1 arrayAttributes contains two attributes
addAttributeToVector(v, symbolTable, Constants.XSD_STRING,
new QName(Constants.URI_SOAP12_ENC, "arrayType"));
addAttributeToVector(v, symbolTable, Constants.XSD_STRING,
new QName(Constants.URI_SOAP12_ENC, "offset"));
}
else if (type.getQName().equals(Constants.SOAP_ARRAY_ATTRS12))
{
// 1.2 arrayAttributes contains two attributes
// the type of "arraySize" is really "2003soapenc:arraySize"
// which is rather of a hairy beast that is not yet supported
// in Axis, so let's just use string; nobody should care for
// now because arraySize wasn't used at all up until this
// bug 23145 was fixed, which had nothing to do, per se, with
// adding support for arraySize
addAttributeToVector(v, symbolTable, Constants.XSD_STRING,
new QName(Constants.URI_SOAP12_ENC, "arraySize"));
addAttributeToVector(v, symbolTable, Constants.XSD_QNAME,
new QName(Constants.URI_SOAP12_ENC, "itemType"));
}
}
}
}
/**
* Return the attribute names and types if any in the node
* The even indices are the attribute types (TypeEntry) and
* the odd indices are the corresponding names (Strings).
* <p/>
* Example:
* <complexType name="Person">
* <sequence>
* <element minOccurs="1" maxOccurs="1" name="Age" type="double" />
* <element minOccurs="1" maxOccurs="1" name="ID" type="xsd:float" />
* </sequence>
* <attribute name="Name" type="string" />
* <attribute name="Male" type="boolean" />
* <attributeGroup ref="s0:MyAttrSet" />
* </complexType>
*
* @param node
* @param symbolTable
* @return
*/
public static Vector getContainedAttributeTypes(Node node,
SymbolTable symbolTable)
{
Vector v = null; // return value
if (node == null)
return null;
// Check for SimpleContent
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
int len = children.getLength();
for (int j = 0; j < len; j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexType"))
{
node = kid;
break;
}
}
}
// Expecting a schema complexType
if (isXSDNode(node, "complexType"))
{
// Under the complexType there could be complexContent/simpleContent
// and extension elements if this is a derived type. Skip over these.
NodeList children = node.getChildNodes();
Node content = null;
int len = children.getLength();
for (int j = 0; j < len; j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "complexContent") || isXSDNode(kid, "simpleContent"))
{
content = kid;
break;
}
}
// Check for extensions or restrictions
if (content != null)
{
children = content.getChildNodes();
len = children.getLength();
for (int j = 0; j < len; j++)
{
Node kid = children.item(j);
if (isXSDNode(kid, "extension") || isXSDNode(kid, "restriction"))
{
node = kid;
break;
}
}
}
// examine children of the node for <attribute> elements
children = node.getChildNodes();
len = children.getLength();
for (int i = 0; i < len; i++)
{
Node child = children.item(i);
if (isXSDNode(child, "attributeGroup"))
{
if (v == null)
v = new Vector();
addAttributeGroupToVector(v, child, symbolTable);
}
else if (isXSDNode(child, "anyAttribute"))
{
// do nothing right now
if (v == null)
v = new Vector();
}
else if (isXSDNode(child, "attribute"))
{
if (v == null)
v = new Vector();
addAttributeToVector(v, child, symbolTable);
}
}
}
return v;
}
// list of all of the XSD types in Schema 2001
/** Field schemaTypes[] */
private static String schemaTypes[] = {
"string", "normalizedString", "token", "byte", "unsignedByte",
"base64Binary", "hexBinary", "integer", "positiveInteger",
"negativeInteger", "nonNegativeInteger", "nonPositiveInteger", "int",
"unsignedInt", "long", "unsignedLong", "short", "unsignedShort",
"decimal", "float", "double", "boolean", "time", "dateTime", "duration",
"date", "gMonth", "gYear", "gYearMonth", "gDay", "gMonthDay", "Name",
"QName", "NCName", "anyURI", "language", "ID", "IDREF", "IDREFS",
"ENTITY", "ENTITIES", "NOTATION", "NMTOKEN", "NMTOKENS",
"anySimpleType"
};
/** Field schemaTypeSet */
private static final Set schemaTypeSet = new HashSet(Arrays.asList(schemaTypes));
/**
* Determine if a string is a simple XML Schema type
*
* @param s
* @return
*/
private static boolean isSimpleSchemaType(String s) {
if (s == null)
return false;
return schemaTypeSet.contains(s);
}
/**
* Determine if a QName is a simple XML Schema type
*
* @param qname
* @return
*/
public static boolean isSimpleSchemaType(QName qname)
{
if ((qname == null) || !Constants.isSchemaXSD(qname.getNamespaceURI()))
return false;
return isSimpleSchemaType(qname.getLocalPart());
}
/**
* Returns the base type of a given type with its symbol table.
* This logic is extracted from JavaTypeWriter's constructor() method
* for reusing.
*
* @param type
* @param symbolTable
* @return
*/
public static TypeEntry getBaseType(TypeEntry type, SymbolTable symbolTable) {
Node node = type.getNode();
TypeEntry base = getComplexElementExtensionBase(node, symbolTable);
if (base == null)
base = getComplexElementRestrictionBase(node, symbolTable);
if (base == null)
{
QName baseQName = getSimpleTypeBase(node);
if (baseQName != null)
base = symbolTable.getType(baseQName);
}
return base;
}
/**
* Returns whether the specified node represents a <xsd:simpleType>
* with a nested <xsd:list itemType="...">.
* @param node
* @return
*/
public static boolean isListWithItemType(Node node)
{
return getListItemType(node) != null;
}
/**
* Returns the value of itemType attribute of <xsd:list> in <xsd:simpleType>
* @param node
* @return
*/
public static QName getListItemType(Node node)
{
if (node == null)
return null;
// If the node kind is an element, dive into it.
if (isXSDNode(node, "element"))
{
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
if (isXSDNode(children.item(j), "simpleType"))
{
node = children.item(j);
break;
}
}
}
// Get the node kind, expecting a schema simpleType
if (isXSDNode(node, "simpleType"))
{
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++)
{
if (isXSDNode(children.item(j), "list"))
{
Node listNode = children.item(j);
org.w3c.dom.Element listElement = (org.w3c.dom.Element) listNode;
String type = listElement.getAttribute("itemType");
if (type.equals(""))
{
Node localType = null;
children = listNode.getChildNodes();
for (j = 0; j < children.getLength() && localType == null; j++)
{
if (isXSDNode(children.item(j), "simpleType"))
localType = children.item(j);
}
if (localType != null)
return getSimpleTypeBase(localType);
return null;
}
//int colonIndex = type.lastIndexOf(":");
//if (colonIndex > 0) {
//type = type.substring(colonIndex + 1);
//}
//return new QName(Constants.URI_2001_SCHEMA_XSD, type + "[]");
return Utils.getQNameFromPrefixedName(node, type);
}
}
}
return null;
}
/*
* check whether node should be namespace qualified or not by checking for "form"
* attribute. If "form" attribute not specified, the defaultAnswer is returned.
*/
public static boolean shouldWeNamespaceQualifyNode(Node elementNode, boolean defaultAnswer)
{
if (null == elementNode || elementNode.getNodeType() != Node.ELEMENT_NODE)
return defaultAnswer;
// Ensure node represents an "element" node. If not, get the parent.
if (!elementNode.getLocalName().equals("element"))
return shouldWeNamespaceQualifyNode(elementNode.getParentNode(), defaultAnswer);
String form = Utils.getAttribute(elementNode, "form");
if (form != null)
{
if (form.equals("qualified"))
return true;
else
return false;
}
else
return defaultAnswer;
}
/*
* Find out whether schema's elementFormDefault is "qualified" or not. This is done by
* recursively interrogating parent nodes until it is found or not.
*/
public static boolean isElementFormDefaultQualified(Node elementNode)
{
if (elementNode != null)
{
String def = Utils.getScopedAttribute(elementNode, "elementFormDefault");
if ((def != null) && def.equals("qualified"))
return true;
}
return false;
}
/*
* Find out whether schema's attributeFormDefault is "qualified" or not. This is done by
* recursively interrogating parent nodes until it is found or not.
*/
public static boolean isAttributeFormDefaultQualified(Node attributeNode)
{
if (attributeNode != null)
{
String def = Utils.getScopedAttribute(attributeNode, "attributeFormDefault");
if ((def != null) && def.equals("qualified"))
return true;
}
return false;
}
}