summaryrefslogtreecommitdiffstats
path: root/sdo-cpp/trunk/runtime/core/src/commonj/sdo/SDOSchemaSAX2Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sdo-cpp/trunk/runtime/core/src/commonj/sdo/SDOSchemaSAX2Parser.cpp')
-rw-r--r--sdo-cpp/trunk/runtime/core/src/commonj/sdo/SDOSchemaSAX2Parser.cpp1434
1 files changed, 1434 insertions, 0 deletions
diff --git a/sdo-cpp/trunk/runtime/core/src/commonj/sdo/SDOSchemaSAX2Parser.cpp b/sdo-cpp/trunk/runtime/core/src/commonj/sdo/SDOSchemaSAX2Parser.cpp
new file mode 100644
index 0000000000..a36fffd1b9
--- /dev/null
+++ b/sdo-cpp/trunk/runtime/core/src/commonj/sdo/SDOSchemaSAX2Parser.cpp
@@ -0,0 +1,1434 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/* $Rev$ $Date$ */
+
+#include "libxml/uri.h"
+#include "commonj/sdo/SDOSchemaSAX2Parser.h"
+#include "commonj/sdo/XSDPropertyInfo.h"
+#include "commonj/sdo/XSDTypeInfo.h"
+#include "commonj/sdo/SDORuntimeException.h"
+#include "commonj/sdo/Logging.h"
+#include "commonj/sdo/SDOUtils.h"
+
+
+#include <stdio.h>
+
+extern "C" {
+ void sdo_error(void *ctx, const char *msg, ...);
+}
+
+namespace commonj
+{
+ namespace sdo
+ {
+
+ using internal::XSDTypeInfo;
+ using internal::TypeDefinitionsImpl;
+ using internal::TypeDefinitionImpl;
+ using internal::XSDPropertyInfo;
+ using internal::PropertyDefinitionImpl;
+ using internal::XMLDAS_TypeDefs;
+ using internal::SDOUtils;
+
+ SDOSchemaSAX2Parser::SDOSchemaSAX2Parser(SchemaInfo& schemaInf,
+ ParserErrorSetter* insetter,
+ PARSED_LOCATIONS& parsedLocs,
+ DEFINED_NAMESPACES& definedNSs)
+ : schemaInfo(schemaInf),
+ SAX2Parser(insetter),
+ parsedLocations(parsedLocs),
+ definedNamespaces(definedNSs)
+ {
+ bInSchema = false;
+ bInvalidElement = false;
+ bInInvalidContent = false;
+ bInvalidList = false;
+ inGroup = 0;
+ preParsing = true;
+ }
+
+ SDOSchemaSAX2Parser::~SDOSchemaSAX2Parser()
+ {
+ }
+
+
+ void SDOSchemaSAX2Parser::storeStartElementEvent(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+ // copy the event to as list for replay.
+ if (currentGroup)
+ {
+ currentGroup->events.push_back(GroupEvent(localname,
+ prefix,
+ URI,
+ namespaces,
+ attributes));
+ }
+
+ }
+
+ void SDOSchemaSAX2Parser::storeEndElementEvent(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI)
+ {
+ // copy the event to as list for replay.
+ if (currentGroup)
+ {
+ currentGroup->events.push_back(GroupEvent(localname, prefix, URI));
+ }
+
+ }
+
+ void SDOSchemaSAX2Parser::replayEvents(
+ const SDOXMLString& uri,
+ const SDOXMLString& name,
+ bool isGroup,
+ const SAX2Attributes& groupAttributes)
+ {
+ for (unsigned int i=0;i< groupList.size(); i++)
+ {
+ if (groupList[i].isAttributeGroup != isGroup)
+ {
+ if (
+ (!name.isNull() && name.equals(groupList[i].name))
+ &&
+ (
+ (uri.isNull() && groupList[i].uri.isNull())
+ || uri.equals(groupList[i].uri))
+ )
+ {
+ // Determine the maxOccurs value from the <group ref=... definition
+ bool isMany = false;
+ const SAX2Attribute* groupMaxOccurrs = groupAttributes.getAttribute("maxOccurs");
+ if (groupMaxOccurrs != 0 &&
+ !groupMaxOccurrs->getValue().equalsIgnoreCase("1"))
+ {
+ isMany = true;
+ }
+
+ int level = 0;
+
+ for (unsigned int j=0;j< groupList[i].events.size();j++)
+ {
+ if (groupList[i].events[j].isStartEvent)
+ {
+ // For top level <choice> or <sequence> we need to add the maxOccurrs
+ // attribute from the group definition if it was "many"
+ if ((level == 0) && isMany)
+ {
+ if (groupList[i].events[j].localname.equalsIgnoreCase("choice")
+ || groupList[i].events[j].localname.equalsIgnoreCase("sequence"))
+ {
+ // Add maxOccurs attribute to list
+ groupList[i].events[j].attributes.addAttribute(*groupMaxOccurrs);
+ }
+ }
+
+ startElementNs(
+ (const SDOXMLString&)
+ groupList[i].events[j].localname,
+ (const SDOXMLString&)
+ groupList[i].events[j].prefix,
+ (const SDOXMLString&)
+ groupList[i].events[j].URI,
+ (const SAX2Namespaces&)
+ groupList[i].events[j].namespaces,
+ (const SAX2Attributes&)
+ groupList[i].events[j].attributes);
+
+ level++;
+ }
+ else
+ {
+ endElementNs(
+ (const SDOXMLString&)
+ groupList[i].events[j].localname,
+ (const SDOXMLString&)
+ groupList[i].events[j].prefix,
+ (const SDOXMLString&)
+ groupList[i].events[j].URI);
+
+ level--;
+ }
+ }
+ return;
+ }
+ }
+ }
+ // no group found
+ if (setter)
+ {
+ char *msg = new char[strlen((const char*)name) + 32];
+ if (msg)
+ {
+ sprintf(msg,"Use of undefined group %s",
+ (const char*)name);
+ setter->setError( msg );
+ delete[] msg;
+ }
+ }
+ }
+
+ // ============================================================================
+ // endDocument
+ // ============================================================================
+ void SDOSchemaSAX2Parser::endDocument()
+ {
+ preParsing=!preParsing;
+ schemaInfo.getSchemaNamespaces().empty();
+ }
+
+
+ // ============================================================================
+ // startElementNS
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startElementNs(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+ LOGINFO_1( INFO,"SchemaParser:startElementNs:%s",(const char*)localname);
+
+ if (URI.equalsIgnoreCase("http://www.w3.org/2001/XMLSchema"))
+ {
+
+ ///////////////////////////////////////////////////////////////////////
+ // Handle schema
+ // Set the URI from the targetNamespace of the xsd:schema element
+ // Remember namespace mappings
+ // Create the root Type
+ ///////////////////////////////////////////////////////////////////////
+
+
+ if (localname.equalsIgnoreCase("schema"))
+ {
+ bInSchema = true;
+ // Handle namespace definitions
+
+
+ schemaInfo.getSchemaNamespaces().merge(namespaces);
+
+ // Handle attributes
+ for (int i=0; i < attributes.size(); i++)
+ {
+ if (attributes[i].getName().equalsIgnoreCase("targetNamespace"))
+ {
+ schemaInfo.setTargetNamespaceURI(attributes[i].getValue());
+ }
+
+ if (attributes[i].getName().equalsIgnoreCase("elementFormDefault"))
+ {
+ if (attributes[i].getValue().equals("qualified"))
+ {
+ schemaInfo.setElementFormDefaultQualified(true);
+ }
+ }
+ }
+
+ currentType.uri = schemaInfo.getTargetNamespaceURI();
+ currentType.name = "RootType";
+ currentType.localname="RootType";
+ definedNamespaces.push_back(currentType.uri);
+ return;
+
+ } // end schema handling
+ if (preParsing)
+ {
+ // we are now pre-parsing groups so that we can allow them to be
+ // defined after use.
+
+ if (inGroup > 0)
+ {
+ if ( localname.equalsIgnoreCase("group")
+ || localname.equalsIgnoreCase("attributeGroup"))
+ {
+ inGroup++;
+ }
+ // check for a group reference first
+ // we are inside a group....
+ storeStartElementEvent(
+ localname,
+ prefix,
+ URI,
+ namespaces,
+ attributes);
+ return;
+ }
+
+ if ( localname.equalsIgnoreCase("group")
+ || localname.equalsIgnoreCase("attributeGroup"))
+ {
+ inGroup++;
+ int i;
+ for (i=0; i < attributes.size(); i++)
+ {
+ if (attributes[i].getName().equalsIgnoreCase("ref"))
+ {
+ // dont store references.
+ return;
+ }
+ }
+
+ groupList.insert(groupList.begin(),GroupDefinition());
+ currentGroup = &groupList[0];
+
+ if (localname.equalsIgnoreCase("group"))
+ currentGroup->isAttributeGroup = false;
+ else currentGroup->isAttributeGroup = true;
+
+ for (i=0; i < attributes.size(); i++)
+ {
+ if (attributes[i].getName().equalsIgnoreCase("name"))
+ {
+ currentGroup->uri = schemaInfo.getTargetNamespaceURI();
+ currentGroup->name = attributes[i].getValue();
+ }
+ }
+ }
+ } // end of preParsing groups.
+ else
+ {
+ if (inGroup == 0)
+ {
+ // Handle <import> of other schema
+ if (localname.equalsIgnoreCase("import"))
+ {
+ // TODO - import and include treated equally for now - need to
+ // separate out the namespace info for import
+ startInclude(localname, prefix, URI, namespaces, attributes);
+ }
+
+ // Handle <include> of other schema
+ else if (localname.equalsIgnoreCase("include"))
+ {
+ startInclude(localname, prefix, URI, namespaces, attributes);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Handle elements and attributes
+ // These become Properties of the current Type
+ // ?? Any special handling of global elements???
+ ///////////////////////////////////////////////////////////////////////
+ else if (localname.equalsIgnoreCase("element"))
+ {
+ if (!bInInvalidContent) startElement(localname, prefix, URI, namespaces, attributes);
+ }
+ else if (localname.equalsIgnoreCase("attribute"))
+ {
+ if (!bInInvalidContent) startAttribute(localname, prefix, URI, namespaces, attributes);
+ }
+ else if (localname.equalsIgnoreCase("any")
+ || localname.equalsIgnoreCase("anyAttribute"))
+ {
+ // the type containing this is to be created as open
+ if (!bInInvalidContent) currentType.isOpen = true;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // Handle complexType
+ // These become new types
+ ///////////////////////////////////////////////////////////////////////
+ else if (localname.equalsIgnoreCase("complexType"))
+ {
+ if (!bInInvalidContent) startComplexType(localname, prefix, URI, namespaces, attributes);
+ } // end complexType handling
+
+ else if (localname.equalsIgnoreCase("choice")
+ || localname.equalsIgnoreCase("sequence")
+ || localname.equalsIgnoreCase("all"))
+ {
+ if (!bInInvalidContent) startGroup(localname, prefix, URI, namespaces, attributes);
+ } // end Group handling
+
+ else if ( localname.equalsIgnoreCase("group")
+ || localname.equalsIgnoreCase("attributeGroup"))
+ {
+
+ int i;
+ for (i=0; i < attributes.size(); i++)
+ {
+ if (attributes[i].getName().equalsIgnoreCase("ref"))
+ {
+ XMLQName qname(attributes[i].getValue(),
+ schemaInfo.getSchemaNamespaces(),
+ namespaces);
+ if (qname.getURI().isNull())
+ {
+ replayEvents(schemaInfo.getTargetNamespaceURI(), qname.getLocalName(),
+ localname.equalsIgnoreCase("group"), attributes);
+ }
+ else
+ {
+ replayEvents(qname.getURI(), qname.getLocalName(),
+ localname.equalsIgnoreCase("group"), attributes);
+ }
+ }
+ }
+ inGroup++;
+ // if theres no 'ref' then its a group definition, and we
+ // already pre-parsed it.
+ }
+ else if (localname.equalsIgnoreCase("list"))
+ {
+ startList(
+ localname,
+ prefix,
+ URI,
+ namespaces,
+ attributes);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Handle simpleType
+ // These become new types
+ ///////////////////////////////////////////////////////////////////////
+ else if (localname.equalsIgnoreCase("simpleType"))
+ {
+ if (!bInInvalidContent) startSimpleType(localname, prefix, URI, namespaces, attributes);
+ } // end complexType handling
+
+ else if (localname.equalsIgnoreCase("restriction"))
+ {
+ if (!bInInvalidContent) startRestriction(localname, prefix, URI, namespaces, attributes);
+ }
+
+ else if (localname.equalsIgnoreCase("extension"))
+ {
+ if (!bInInvalidContent) startExtension(localname, prefix, URI, namespaces, attributes);
+ }
+ // Handle <import> of other schema
+ else if (localname.equalsIgnoreCase("union"))
+ {
+ // TODO - unions not yet properly supported - for now, whatever the
+ // enclosing thing is, we will make it an extended primitive based on
+ // String.
+ bInInvalidContent = true;
+ //if (setter)
+ //{
+ // setter->setError("Schema contains a union which is not yet implemented");
+ //}
+
+ currentType.parentTypeUri = "commonj.sdo";
+ currentType.parentTypeName = "String";
+ currentType.isRestriction = true;
+
+ }
+ }
+ }
+ }
+ else // not in schema - check for any extra namespaces
+ {
+ schemaInfo.getSchemaNamespaces().merge(namespaces);
+ }
+
+ }
+
+
+ // ============================================================================
+ // endElementNs
+ // ============================================================================
+ void SDOSchemaSAX2Parser::endElementNs(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI)
+ {
+ LOGINFO_1( INFO,"SchemaParser:endElementNs:%s",(const char*)localname);
+
+ if (URI.equalsIgnoreCase("http://www.w3.org/2001/XMLSchema"))
+ {
+ if (localname.equalsIgnoreCase("schema"))
+ {
+ bInSchema = false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Handle complexType
+ // Pop the Type off our stack
+ ///////////////////////////////////////////////////////////////////////
+
+ // We do not support unions, so all inside a union, plus the containing
+ // element are invalid for now.
+ //
+ if (!bInInvalidContent)
+ {
+ if (preParsing)
+ {
+ if (inGroup > 0)
+ {
+ if (localname.equalsIgnoreCase("group")
+ || localname.equalsIgnoreCase("attributeGroup"))
+ {
+ inGroup--;
+ if (inGroup < 0)inGroup = 0; // should never happen.
+ }
+ if (inGroup > 0) // still need to store end of group ref
+ {
+ storeEndElementEvent(
+ localname,
+ prefix,
+ URI);
+ }
+ }
+ }
+ else
+ {
+ if (localname.equalsIgnoreCase("group")
+ || localname.equalsIgnoreCase("attributeGroup"))
+ {
+ inGroup--;
+ if (inGroup < 0) inGroup = 0;
+ // outside of preparse, dont need to do anything.
+ }
+ else if (inGroup == 0)
+ {
+ if (localname.equalsIgnoreCase("complexType"))
+ {
+ if (!bInvalidElement) defineType();
+ } // end complexType handling
+ else if (localname.equalsIgnoreCase("simpleType"))
+ {
+ if (!bInvalidElement) defineType();
+ }
+ else if (localname.equalsIgnoreCase("schema"))
+ {
+ if (!bInvalidElement) defineType();
+ } // end complexType handling
+ else if (localname.equalsIgnoreCase("element")
+ || localname.equalsIgnoreCase("attribute"))
+ {
+ // PropertyDefinition should now be complete
+ if (!bInvalidElement) defineProperty();
+ }
+ else if (localname.equalsIgnoreCase("choice")
+ || localname.equalsIgnoreCase("sequence")
+ || localname.equalsIgnoreCase("all"))
+ {
+ if (!bInvalidElement) currentType.isMany = false;
+ }
+ else if (localname.equalsIgnoreCase("list"))
+ {
+ // PropertyDefinition should now be complete
+ if (!bInvalidList) defineProperty();
+ bInvalidList = false;
+ }
+ bInvalidElement = false;
+ }
+ }
+
+ } // bInUnsupportedContent
+ if (localname.equalsIgnoreCase("union"))
+ {
+ bInInvalidContent = false;
+ // the enclosing element is not useful
+ // TODO - Instead of making the union invalid, we make it an
+ // extended primitive based on string - so its no longer invalid.
+ //bInvalidElement = true;
+ }
+ }
+
+ }
+
+ int SDOSchemaSAX2Parser::parseURI(const SDOXMLString& location, const SDOXMLString& base)
+ {
+ xmlChar* absoluteUri = xmlBuildURI(location, base);
+ if (! absoluteUri)
+ {
+ throw SDOFileNotFoundException(TUSCANY_SDO_EINFO,
+ location);
+ }
+ SDOXMLString absUri(absoluteUri);
+ xmlFree(absoluteUri);
+
+ // Determine if this location has been parsed already
+ PARSED_LOCATIONS::iterator iter;
+ iter = parsedLocations.find(absUri);
+ if (iter != parsedLocations.end())
+ {
+ schemaInfo.setTargetNamespaceURI(iter->second);
+ return 0;
+ }
+
+
+ try
+ {
+ int rc = parse(absUri);
+ // add new location to map
+ parsedLocations[absUri] = schemaInfo.getTargetNamespaceURI();
+ return rc;
+ }
+ catch (SDORuntimeException) {}
+
+ return -1;
+ }
+
+ // ============================================================================
+ // startInclude
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startInclude(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+ LOGINFO_1( INFO,"SchemaParser:startInclude:%s",(const char*)localname);
+
+ if (!bInSchema) return;
+
+
+ SDOXMLString importNamespace = attributes.getValue("namespace");
+ SDOXMLString schemaLocation = attributes.getValue("schemaLocation");
+
+ if (localname.equalsIgnoreCase("import")
+ && !importNamespace.isNull())
+ {
+ // Do not attempt to import namespaces alredy defined
+ for (unsigned int i = 0; i < definedNamespaces.size(); i++)
+ {
+ if (definedNamespaces[i].equals(importNamespace))
+ {
+ return;
+ }
+ }
+ }
+
+ SchemaInfo schemaInf;
+ SDOSchemaSAX2Parser schemaParser(schemaInf, setter, parsedLocations, definedNamespaces);
+
+ if (!schemaLocation.isNull())
+ {
+ if (0 != schemaParser.parseURI(schemaLocation, getCurrentFile()))
+ return;
+ }
+ else
+ {
+ // schemaLocation isn't present. Try loading namespace for import
+ if (localname.equalsIgnoreCase("import")
+ && !importNamespace.isNull())
+ {
+ if (0 != schemaParser.parseURI(importNamespace, SDOXMLString()))
+ return;
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ // Add the parsed types to this parsers list
+ TypeDefinitionsImpl& typedefs = schemaParser.getTypeDefinitions();
+ XMLDAS_TypeDefs types = typedefs.types;
+ XMLDAS_TypeDefs::iterator iter;
+ for (iter=types.begin(); iter != types.end(); iter++)
+ {
+ if ((*iter).second.name.equals("RootType")
+ && currentType.name.equals("RootType")
+ && (*iter).second.uri.equals(currentType.uri))
+ {
+ // This must be true for an import/include to be
+ // legally positioned
+
+ XMLDAS_TypeDefs::iterator find = typeDefinitions.types.find(
+ (*iter).first);
+
+ std::list<PropertyDefinitionImpl>::iterator propit;
+ std::list<PropertyDefinitionImpl>::iterator currpropit;
+ bool found;
+
+ for (propit = (*iter).second.properties.begin() ;
+ propit != (*iter).second.properties.end(); ++ propit)
+ {
+ found = false;
+ // do not merge properties whose names clash
+ for ( currpropit = currentType.properties.begin();
+ currpropit != currentType.properties.end();
+ ++currpropit)
+ {
+ if ((*currpropit).name.equals((*propit).name))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ currentType.properties.push_back(*propit);
+ }
+ }
+ }
+ else
+ {
+ typeDefinitions.types.insert(*iter);
+ }
+ }
+
+ }
+
+
+ // ============================================================================
+ // startList
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startList(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+
+ LOGINFO_1( INFO,"SchemaParser:startList:%s",(const char*)localname);
+
+ if (!bInSchema) return;
+
+ // invent a property called "values" to hold the list
+
+ SDOXMLString typeName = attributes.getValue("itemType");
+
+ if (typeName.isNull())
+ {
+ // we do not support lists with no item type (yet).
+ if (setter)
+ {
+ setter->setError("Schema contains a list with no type - not supported");
+ }
+ bInvalidList = true;
+ return;
+ }
+
+ currentType.dataType = false;
+ currentType.isFromList = true;
+
+ // attribute to set the list type
+ // define an internal property to hold the list
+ PropertyDefinitionImpl thisProperty;
+ thisProperty.name = "values";
+ thisProperty.localname = "values";
+ thisProperty.isContainment = false;
+ thisProperty.isElement=true;
+ thisProperty.isMany = true;
+
+ XMLQName qname = resolveTypeName(
+ typeName,
+ namespaces,
+ thisProperty.typeUri,
+ thisProperty.typeName);
+ thisProperty.fullTypeName = typeName;
+
+ setCurrentProperty(thisProperty);
+
+ }
+
+ // ============================================================================
+ // startElement
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startElement(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+
+ if (!bInSchema) return;
+
+ PropertyDefinitionImpl thisProperty;
+
+ LOGINFO_1( INFO,"SchemaParser:startElement:%s",(const char*)localname);
+
+ thisProperty.isElement = true;
+
+ setName(attributes,
+ thisProperty.name,
+ thisProperty.localname);
+
+ // Set the property's namespace if elementForm is "qualified"
+ bool elementFormQualified = schemaInfo.isElementFormDefaultQualified();
+ SDOXMLString elementForm = attributes.getValue("form");
+ if (!elementForm.isNull())
+ {
+ elementFormQualified = false;
+ if (elementForm.equals("qualified"))
+ {
+ elementFormQualified = true;
+ }
+ }
+
+ if (elementFormQualified
+ || currentType.name.equals("RootType"))
+ {
+ thisProperty.namespaceURI = schemaInfo.getTargetNamespaceURI();
+ }
+
+ setType(thisProperty, attributes, namespaces);
+
+ // Set isMany. currentType.isMany = true indicates we are in a
+ // group definition (sequence/choice) with maxOccurs>1
+ if (currentType.isMany)
+ {
+ thisProperty.isMany = true;
+ }
+ else
+ {
+ SDOXMLString maxOccurs = attributes.getValue("maxOccurs");
+ if (!maxOccurs.isNull())
+ {
+ if (!maxOccurs.equalsIgnoreCase("1"))
+ {
+ thisProperty.isMany = true;
+ }
+ }
+ }
+
+ // find aliases
+ thisProperty.aliases = attributes.getValue("aliasName");
+
+ // mark this as a substitution group.
+ // TODO - what about properties which have already been set into the tree,
+ // and might have a substitution?
+
+ SDOXMLString substituteName = attributes.getValue("substitutionGroup");
+ if (! substituteName.isNull())
+ {
+ XMLQName qname = resolveTypeName(
+ substituteName,
+ namespaces,
+ thisProperty.substituteUri,
+ thisProperty.substituteName);
+ thisProperty.isSubstitute=true;
+ }
+
+ // count the number of elements in the group
+ if (currentType.isMany)
+ {
+ currentType.groupElementCount++;
+ }
+
+ setCurrentProperty(thisProperty);
+
+ }
+
+ // ============================================================================
+ // startAttribute
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startAttribute(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+
+ LOGINFO_1( INFO,"SchemaParser:startAttribute:%s",(const char*)localname);
+
+ if (!bInSchema) return;
+
+ PropertyDefinitionImpl thisProperty;
+
+ thisProperty.isElement = false;
+
+ setName(attributes,
+ thisProperty.name,
+ thisProperty.localname);
+
+ thisProperty.namespaceURI = schemaInfo.getTargetNamespaceURI();
+
+ setType(thisProperty, attributes, namespaces);
+
+ setCurrentProperty(thisProperty);
+ }
+
+ // ============================================================================
+ // startComplexType
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startComplexType(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+ LOGINFO_1( INFO,"SchemaParser:startComplexType:%s",(const char*)localname);
+
+ if (!bInSchema) return;
+
+ TypeDefinitionImpl thisType; // set defaults
+ thisType.uri=schemaInfo.getTargetNamespaceURI();
+
+ setTypeName(thisType, attributes,namespaces);
+
+
+
+ for (int i=0; i < attributes.size(); i++)
+ {
+ // If sdo:sequence="true" or mixed="true" it is sequenced
+ if ( (attributes[i].getUri().equalsIgnoreCase("commonj.sdo/xml")
+ && attributes[i].getName().equalsIgnoreCase("sequence"))
+ || attributes[i].getName().equalsIgnoreCase("mixed"))
+ {
+ if (attributes[i].getValue().equals("true"))
+ {
+ thisType.isSequenced = true;
+ }
+ }
+ // If abstract="true" it is abstract
+ else if (attributes[i].getName().equalsIgnoreCase("abstract"))
+ {
+ if (attributes[i].getValue().equals("true"))
+ {
+ thisType.isAbstract = true;
+ }
+ }
+ else if (attributes[i].getName().equalsIgnoreCase("aliasName"))
+ {
+ thisType.aliases = attributes[i].getValue();
+ }
+ }
+
+ setCurrentType(thisType);
+ }
+
+ // ============================================================================
+ // startSimpleType
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startSimpleType(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+ LOGINFO_1( INFO,"SchemaParser:startSimpleType:%s",(const char*)localname);
+
+ if (!bInSchema) return;
+
+ TypeDefinitionImpl thisType; // set defaults
+ thisType.uri=schemaInfo.getTargetNamespaceURI();
+ thisType.dataType = true;
+
+ for (int i=0; i < attributes.size(); i++)
+ {
+ // If abstract="true" it is abstract
+ if (attributes[i].getName().equalsIgnoreCase("abstract"))
+ {
+ if (attributes[i].getValue().equals("true"))
+ {
+ thisType.isAbstract = true;
+ }
+ }
+ else if (attributes[i].getName().equalsIgnoreCase("aliasName"))
+ {
+ thisType.aliases = attributes[i].getValue();
+ }
+ }
+ setTypeName(thisType, attributes,namespaces);
+
+ // see if the type is going to be abstract...
+
+
+ setCurrentType(thisType);
+ }
+
+ // ============================================================================
+ // startRestriction
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startRestriction(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+ LOGINFO_1( INFO,"SchemaParser:startRestriction:%s",(const char*)localname);
+
+ if (!bInSchema) return;
+
+ SDOXMLString base = attributes.getValue("base");
+ if (!base.isNull())
+ {
+ // Resolve typename to uri:name
+ XMLQName qname = resolveTypeName(
+ base,
+ namespaces,
+ currentType.parentTypeUri,
+ currentType.parentTypeName);
+
+ currentType.isRestriction=true;
+
+
+ if(qname.getLocalName().equals("QName"))
+ {
+ currentType.isQName = true;
+ }
+ }
+ }
+
+ // ============================================================================
+ // startExtension
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startExtension(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+ LOGINFO_1( INFO,"SchemaParser:startExtension:%s",(const char*)localname);
+
+ if (!bInSchema) return;
+
+ SDOXMLString base = attributes.getValue("base");
+ if (!base.isNull())
+ {
+ SDOXMLString typeUri;
+ SDOXMLString typeName;
+ // Resolve typename to uri:name
+ XMLQName qname = resolveTypeName(
+ base,
+ namespaces,
+ typeUri,
+ typeName);
+
+ // If extending a simple type (an SDO DataType) we create a
+ // Property named "value" of this type rather than set the
+ // simple type as a base
+ currentType.isRestriction=false;
+
+ // ?? Does this only apply within a <simpleContent> tag??
+ if (typeUri.equalsIgnoreCase(SDOUtils::sdoURI))
+ {
+ // here the type needs to be flagged so that
+ // we know to serialize this property as an element with
+ // just the contents <element>abc</element> rather than
+ // value=abc
+
+
+ PropertyDefinitionImpl thisProperty;
+ thisProperty.name = "value";
+ thisProperty.localname = "value";
+ thisProperty.typeUri = typeUri;
+ thisProperty.typeName = typeName;
+ thisProperty.fullTypeName = base;
+ thisProperty.isContainment = false;
+ thisProperty.isElement=true;
+
+ currentType.isExtendedPrimitive= true;
+
+ if(qname.getLocalName().equals("QName"))
+ {
+ thisProperty.isQName = true;
+ }
+
+ setCurrentProperty(thisProperty);
+ defineProperty();
+ }
+ else
+ {
+ currentType.parentTypeUri = typeUri;
+ currentType.parentTypeName = typeName;
+ }
+ }
+ }
+
+ // ============================================================================
+ // startGroup
+ // ============================================================================
+ void SDOSchemaSAX2Parser::startGroup(
+ const SDOXMLString& localname,
+ const SDOXMLString& prefix,
+ const SDOXMLString& URI,
+ const SAX2Namespaces& namespaces,
+ const SAX2Attributes& attributes)
+ {
+ LOGINFO_1( INFO,"SchemaParser:startGroup:%s",(const char*)localname);
+
+ if (!bInSchema) return;
+
+ SDOXMLString maxOccurs = attributes.getValue("maxOccurs");
+ if (!maxOccurs.isNull())
+ {
+ if (!maxOccurs.equalsIgnoreCase("1"))
+ {
+ currentType.isMany = true;
+ }
+ }
+ }
+
+ // ============================================================================
+ // setCurrentType
+ // ============================================================================
+ void SDOSchemaSAX2Parser::setCurrentType(const TypeDefinitionImpl& type)
+ {
+ typeStack.push(currentType);
+ currentType = type;
+ }
+
+ // ============================================================================
+ // defineType
+ // ============================================================================
+ void SDOSchemaSAX2Parser::defineType()
+ {
+ // Set this Type as sequenced of more than one element in a group definition
+ if (currentType.groupElementCount > 1)
+ {
+ currentType.isSequenced = true;
+ }
+
+ SDOXMLString typeQname = TypeDefinitionsImpl::getTypeQName(currentType.uri, currentType.localname);
+ typeDefinitions.types[typeQname] = currentType;
+
+ if (currentProperty.typeName.isNull())
+ {
+ // Set the type name to the name of this type
+ currentProperty.typeUri = currentType.uri;
+ currentProperty.typeName = currentType.localname;
+ }
+
+ if (typeStack.size() != 0)
+ {
+ currentType = typeStack.top();
+ typeStack.pop();
+ }
+ else
+ {
+ currentType = TypeDefinitionImpl();
+ }
+ }
+
+ // ============================================================================
+ // setCurrentProperty
+ // ============================================================================
+ void SDOSchemaSAX2Parser::setCurrentProperty(const PropertyDefinitionImpl& prop)
+ {
+ propertyStack.push(currentProperty);
+ currentProperty = prop;
+ }
+
+ // ============================================================================
+ // defineProperty
+ // ============================================================================
+ void SDOSchemaSAX2Parser::defineProperty()
+ {
+
+ if (currentProperty.typeName.isNull())
+ {
+ // Set the type of this property to default (sdo:String)
+ currentProperty.typeUri = SDOUtils::sdoURI;
+ currentProperty.typeName = "String";
+ }
+
+ if (currentProperty.localname.isNull())
+ currentProperty.localname = currentProperty.typeName;
+
+ // Set isMany if property isMany OR if containing type isMany
+ // NOTE: The above comment is as per the SDO2.0 spec however this does not
+ // work when serializing a sequence containing a single-valued property and
+ // then deserializing.
+ // currentProperty.isMany = currentProperty.isMany || currentType.isMany;
+
+ currentType.properties.push_back(currentProperty);
+ if (propertyStack.size() != 0)
+ {
+ currentProperty = propertyStack.top();
+ propertyStack.pop();
+ }
+ else
+ currentProperty = PropertyDefinitionImpl();
+
+ }
+
+ // ============================================================================
+ // setDefault
+ // ============================================================================
+ void SDOSchemaSAX2Parser::setDefault(
+ PropertyDefinitionImpl& thisProperty,
+ const SAX2Attributes& attributes)
+ {
+ thisProperty.defaultValue = attributes.getValue("fixed");
+ if (!thisProperty.defaultValue.isNull())
+ {
+ thisProperty.isReadOnly = true;
+ }
+ else
+ {
+ thisProperty.defaultValue = attributes.getValue("default");
+ }
+ }
+
+ // ============================================================================
+ // setName
+ // ============================================================================
+ void SDOSchemaSAX2Parser::setName(
+ const SAX2Attributes& attributes,
+ SDOXMLString& sdoname,
+ SDOXMLString& localname)
+ {
+ for (int i=0; i < attributes.size(); i++)
+ {
+ // Handle sdo: annotations
+ if (attributes[i].getUri().equalsIgnoreCase("commonj.sdo/xml"))
+ {
+ // sdo:name overrides the property name
+ if (attributes[i].getName().equalsIgnoreCase("name"))
+ {
+ sdoname = attributes[i].getValue();
+ }
+ }
+ else
+ {
+
+ if (attributes[i].getName().equalsIgnoreCase("name"))
+ {
+ localname = attributes[i].getValue();
+ // If name is already set it must have been an
+ // override using sdo:name
+ if (sdoname.isNull())
+ {
+ sdoname = localname;
+ }
+ }
+ }
+ }
+
+ }
+
+ // ============================================================================
+ // setType
+ // ============================================================================
+ void SDOSchemaSAX2Parser::setType(
+ PropertyDefinitionImpl& property,
+ const SAX2Attributes& attributes,
+ const SAX2Namespaces& namespaces)
+ {
+ property.fullLocalTypeName = attributes.getValue("type");
+ if (!property.fullLocalTypeName.isNull())
+ {
+ XMLQName qname(property.fullLocalTypeName,schemaInfo.getSchemaNamespaces(), namespaces);
+ if (qname.getLocalName().equals("IDREF")
+ || qname.getLocalName().equals("IDREFS"))
+ {
+ property.fullTypeName = attributes.getValue("commonj.sdo/xml","propertyType");
+
+ property.isIDREF = true;
+ property.isContainment = false;
+
+ if (qname.getLocalName().equals("IDREFS"))
+ {
+ property.isMany = true;
+ }
+ }
+ else if (qname.getLocalName().equals("anyURI"))
+ {
+ property.fullTypeName = attributes.getValue("commonj.sdo/xml","propertyType");
+ }
+ else if (qname.getLocalName().equals("ID"))
+ {
+ property.isID = true;
+ currentType.IDPropertyName = property.name;
+ }
+
+ else
+ {
+ property.fullTypeName = attributes.getValue("commonj.sdo/xml","dataType");
+ }
+ }
+
+ else
+ {
+ property.fullLocalTypeName = attributes.getValue("ref");
+ if (!property.fullLocalTypeName.isNull())
+ {
+ property.isReference = true;
+ }
+ }
+
+ if (property.fullTypeName.isNull())
+ {
+ property.fullTypeName = property.fullLocalTypeName;
+ }
+
+ if (!property.fullTypeName.isNull())
+ {
+ // Resolve typename to uri:name
+ XMLQName qname = resolveTypeName(
+ property.fullTypeName,
+ namespaces,
+ property.typeUri,
+ property.typeName);
+
+ if(qname.getLocalName().equals("QName"))
+ {
+ property.isQName = true;
+ }
+ }
+
+ }
+
+ // ============================================================================
+ // setTypeName
+ // ============================================================================
+ void SDOSchemaSAX2Parser::setTypeName(
+ TypeDefinitionImpl& type,
+ const SAX2Attributes& attributes,
+ const SAX2Namespaces& namespaces)
+ {
+ setName(attributes, type.name, type.localname);
+
+
+ // If localname is not set it is anonymous so use the enclosing element name
+ if (type.localname.isNull())
+ {
+ type.localname = currentProperty.name;
+
+ // ensure anonymous type name does not clash with existing type
+ for (int suffix = 1; ; suffix++)
+ {
+ SDOXMLString typeUri = TypeDefinitionsImpl::getTypeQName(type.uri, type.localname);
+ XMLDAS_TypeDefs::iterator it = typeDefinitions.types.find(typeUri);
+ if(it == typeDefinitions.types.end())
+ {
+ break;
+ }
+ char buff[32];
+ sprintf(buff, "%d", suffix);
+ type.localname += buff;
+ }
+ }
+ else
+ {
+ // check for an overriding url in the name
+ int i;
+ if ((i = type.localname.firstIndexOf(':')) > 0)
+ {
+ XMLQName qname(type.localname,
+ schemaInfo.getSchemaNamespaces(),
+ namespaces);
+ type.uri = qname.getURI();
+ type.localname = qname.getLocalName();
+ }
+ }
+
+ // Set SDO name if not specified
+ if (type.name .isNull())
+ {
+ type.name = type.localname ;
+ }
+ else
+ {
+ // check for an overriding url in the name
+ int i;
+ if ((i = type.name.firstIndexOf(':')) > 0)
+ {
+ XMLQName qname(type.name,
+ schemaInfo.getSchemaNamespaces(),
+ namespaces);
+ type.uri = qname.getURI();
+ type.name = qname.getLocalName();
+ }
+ }
+ }
+
+ std::istream& operator>>(std::istream& input, SDOSchemaSAX2Parser& parser)
+ {
+ parser.stream(input);
+
+ return input;
+ }
+
+ std::istringstream& operator>>(std::istringstream& input, SDOSchemaSAX2Parser& parser)
+ {
+ parser.stream(input);
+
+ return input;
+ }
+
+ void SDOSchemaSAX2Parser::stream(std::istream& input)
+ {
+ // override to parse twice for groups
+
+ stream_twice(input);
+ }
+
+
+ int SDOSchemaSAX2Parser::parse(const char* filename)
+ {
+ return parse_twice(filename);
+ }
+
+
+
+ // ============================================================================
+ // resolveTypeName
+ // ============================================================================
+ XMLQName SDOSchemaSAX2Parser::resolveTypeName(
+ const SDOXMLString& fullTypeName,
+ const SAX2Namespaces& namespaces,
+ SDOXMLString& uri,
+ SDOXMLString& name)
+ {
+ XMLQName qname(fullTypeName,
+ schemaInfo.getSchemaNamespaces(),
+ namespaces);
+
+ uri = qname.getURI();
+ name = qname.getLocalName();
+
+ ///////////////////////////////////////////////////////////////////////
+ // Map the xsd types to SDO Types
+ ///////////////////////////////////////////////////////////////////////
+ if (qname.getURI().equalsIgnoreCase("http://www.w3.org/2001/XMLSchema"))
+ {
+ uri = SDOUtils::sdoURI;
+ name = SDOUtils::XSDToSDO((const char*)(qname.getLocalName()));
+ if (name.isNull())
+ {
+ name = "String";
+ }
+
+ }
+
+ // Temporary hack: ChangeSummaryType is ChangeSummary in core
+ else if (qname.getURI().equalsIgnoreCase(SDOUtils::sdoURI))
+ {
+ if (qname.getLocalName().equalsIgnoreCase("ChangeSummaryType"))
+ {
+ name = "ChangeSummary";
+ }
+
+ }
+ else if (qname.getURI().isNull())
+ {
+ uri = schemaInfo.getTargetNamespaceURI();
+ }
+
+ return qname;
+ }
+
+ } // End - namespace sdo
+
+} // End - namespace commonj
+