diff options
Diffstat (limited to 'cpp/src/Freeze/Transform.cpp')
-rw-r--r-- | cpp/src/Freeze/Transform.cpp | 2047 |
1 files changed, 0 insertions, 2047 deletions
diff --git a/cpp/src/Freeze/Transform.cpp b/cpp/src/Freeze/Transform.cpp deleted file mode 100644 index b86db6a0f2e..00000000000 --- a/cpp/src/Freeze/Transform.cpp +++ /dev/null @@ -1,2047 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2001 -// MutableRealms, Inc. -// Huntsville, AL, USA -// -// All Rights Reserved -// -// ********************************************************************** - -#include <Freeze/Transform.h> - -#include <vector> -#include <assert.h> -#include <iostream> -#include <Freeze/Print.h> - -#include <Freeze/ErrorHandler.h> -#include <parsers/DOMParser.hpp> - -using namespace std; - -ostream& -operator<<(ostream& os, const IllegalTransform& ex) -{ - os << "IllegalTransform: file: " << ex.file() << " line: " << ex.line(); - return os; -} - -ostream& -operator<<(ostream& os, const IncompatibleSchema& ex) -{ - os << "IncompatibleSchema: file: " << ex.file() << " line: " << ex.line(); - return os; -} - -ostream& -operator<<(ostream& os, const InvalidSchema& ex) -{ - os << "InvalidSchema: file: " << ex.file() << " line: " << ex.line(); - return os; -} - -ostream& -operator<<(ostream& os, const SchemaViolation& ex) -{ - os << "SchemaViolation: file: " << ex.file() << " line: " << ex.line(); - return os; -} - -static string -toString(const DOMString& s) -{ - char* t = s.transcode(); - string r(t); - delete[] t; - return r; -} - - -typedef ::std::map< ::std::string, DocumentInfo*> DocumentMap; - -typedef ::std::map< ::std::string, ::std::string> PrefixURIMap; - -struct DocumentInfo -{ - DOM_Document document; - PrefixURIMap nsMap; - ::std::string targetNamespace; -}; - -// -// Convert a QName from prefix:local to local@namespaceURI. -// -static string -convertQName(const string& qname, const DocumentInfo* info) -{ - size_t pos = qname.find(':'); - string prefix; - string localName; - if (pos != string::npos) - { - prefix = qname.substr(0, pos); - localName = qname.substr(pos+1); - } - else - { - localName = qname; - } - - PrefixURIMap::const_iterator q = info->nsMap.find(prefix); - if (q == info->nsMap.end()) - { - cout << qname << endl; - // - // No namespace - TODO: not InvalidSchema - it's an - // invalid instance document. - // - throw InvalidSchema(__FILE__, __LINE__); - } - - string n = localName; - n += '@'; - n += q->second; - - return n; -} - -static void -createNSMap(DocumentInfo* info, DOM_Node& root) -{ - static const string targetNamespaceAttrName = "targetNamespace"; - static const string xmlnsAttrName = "xmlns"; - - DOM_NamedNodeMap attributes = root.getAttributes(); - unsigned int max = attributes.getLength(); - for (unsigned int i = 0; i < max; ++i) - { - DOM_Node attribute = attributes.item(i); - string attrName = toString(attribute.getNodeName()); - if (attrName.substr(0, 5) == xmlnsAttrName) - { - string ns; - if (attrName.size() > 5) - { - ns = attrName.substr(6); - } - string uri = toString(attribute.getNodeValue()); - //cout << "adding: " << ns << " " << uri << endl; - info->nsMap.insert(make_pair(ns, uri)); - } - else if (attrName == targetNamespaceAttrName) - { - info->targetNamespace = toString(attribute.getNodeValue()); - } - } -} - -static DOM_Node -findChild(const DOM_Node& parent, const string& namespaceURI, const string& localname) -{ - DOM_NodeList children = parent.getChildNodes(); - for (unsigned int i = 0; i < children.getLength(); ++i) - { - DOM_Node child = children.item(i); - if (toString(child.getNamespaceURI()) == namespaceURI && toString(child.getLocalName()) == localname) - { - return child; - } - } - - return DOM_Node(); -} - -// -// TODO: This is used for abuse. Replace by a real search. -// -static DOM_Node -findChild(const DOM_Node& parent, const string& name) -{ - DOM_NodeList children = parent.getChildNodes(); - for (unsigned int i = 0; i < children.getLength(); ++i) - { - DOM_Node child = children.item(i); - if (toString(child.getNodeName()) == name) - { - return child; - } - } - return DOM_Node(); -} - -static string -getAttributeByName(DOM_Node& node, const string& name) -{ - DOM_NamedNodeMap attributes = node.getAttributes(); - unsigned int max = attributes.getLength(); - for (unsigned int i = 0; i < max; ++i) - { - DOM_Node attribute = attributes.item(i); - string nodeName = toString(attribute.getNodeName()); - if (nodeName == name) - { - return toString(attribute.getNodeValue()); - } - } - - return string(""); -} - -static string -getLengthAttribute(DOM_Node& node) -{ - static const string lengthName = "length"; - return getAttributeByName(node, lengthName); -} - -static string -getTypeAttribute(DOM_Node& node) -{ - static const string typeName = "type"; - return getAttributeByName(node, typeName); -} - -static string -getNameAttribute(DOM_Node& node) -{ - static const string nameName = "name"; - return getAttributeByName(node, nameName); -} - -static string -getValueAttribute(DOM_Node& node) -{ - static const string valueName = "value"; - return getAttributeByName(node, valueName); -} - -static string -findAppinfoType(DOM_Node& node) -{ - DOM_Node child = findChild(node, "xs:annotation"); - if (!child.isNull()) - { - child = findChild(child, "xs:appinfo"); - if (!child.isNull()) - { - child = findChild(child, "type"); - if (!child.isNull()) - { - child = child.getFirstChild(); - if (!child.isNull()) - { - return toString(child.getNodeValue()); - } - } - } - } - - return string(""); -} - -// -// Specific transforms. -// -class NilTransform : public Transform -{ -public: - - NilTransform() - { - } - - virtual void - transform(ostream& os, const DocumentInfo*, const string&, DOM_Node node) - { - if (node.isNull()) - { - throw SchemaViolation(__FILE__, __LINE__); - } - - os << node; - } - - virtual ostream& - print(ostream& os) - { - os << "[nil transform]"; - return os; - } -}; - -// -// This transform is the root transform for marshaled documents. -// -// TODO: complete, rename -// -class InternalTransform : public Transform -{ -public: - - InternalTransform() - { - } - - virtual void - transform(ostream& os, const DocumentInfo*, const string&, DOM_Node node) - { - } - - virtual ostream& - print(ostream& os) - { - os << "[internal transform]"; - return os; - } -}; - -class ElementTransform : public Transform -{ -public: - - ElementTransform(const string& namespaceURI, const string& name, Transform* transform) : - _ns(namespaceURI), - _name(name), - _transform(transform) - { - } - - virtual void - transform(ostream& os, const DocumentInfo* info, const string&, DOM_Node node) - { - _transform->transform(os, info, _name, node); - } - - virtual ostream& - print(ostream& os) - { - os << "[ element: " << name() << ": " << _transform->print(os) << "]"; - return os; - } - - const string& namespaceURI() const { return _ns; } - const string& name() const { return _name; } - -private: - - string _ns; - string _name; - - Transform* _transform; -}; - -class ValidateEnumerationTransform : public Transform -{ -public: - - ValidateEnumerationTransform(const vector<string>& values) : - _values(values) - { - } - - virtual void - transform(ostream& os, const DocumentInfo*, const string&, DOM_Node node) - { - if (node.isNull()) - { - throw SchemaViolation(__FILE__, __LINE__); - } - - DOM_Node child = node.getFirstChild(); - if (child.isNull() || child.getNodeType() != DOM_Node::TEXT_NODE) - { - throw SchemaViolation(__FILE__, __LINE__); - } - string value = toString(child.getNodeValue()); - if (find(_values.begin(), _values.end(), value) == _values.end()) - { - throw IllegalTransform(__FILE__, __LINE__); - } - os << node; - } - - virtual ostream& - print(ostream& os) - { - os << "[validate enumeration]"; - return os; - } - -private: - - vector<string> _values; -}; - -class ValidateIntegerTransform : public Transform -{ -public: - - ValidateIntegerTransform(const string& from, const string& to) : - _from(from), - _to(to) - { - } - - virtual void - transform(ostream& os, const DocumentInfo*, const string&, DOM_Node node) - { - if (node.isNull()) - { - throw SchemaViolation(__FILE__, __LINE__); - } - - DOM_Node child = node.getFirstChild(); - if (child.isNull() || child.getNodeType() != DOM_Node::TEXT_NODE) - { - throw SchemaViolation(__FILE__, __LINE__); - } - string value = toString(child.getNodeValue()); - long v = atol(value.c_str()); - if (_to == "xs:byte") - { - if (v < SCHAR_MIN || v > SCHAR_MAX) - { - throw IllegalTransform(__FILE__, __LINE__); - } - } - else if (_to == "xs:short") - { - if (v < SHRT_MIN || v > SHRT_MAX) - { - throw IllegalTransform(__FILE__, __LINE__); - } - } - else if (_to == "xs:int") - { - if (v < INT_MIN || v > INT_MAX) - { - throw IllegalTransform(__FILE__, __LINE__); - } - } - else if (_to == "xs:long") - { - } - os << node; - } - - virtual ostream& - print(ostream& os) - { - os << "[validate integer: from=" << _from << " to=" << _to << " ]"; - return os; - } - -private: - - string _from; - string _to; -}; - -class ValidateFloatTransform : public Transform -{ -public: - - ValidateFloatTransform(const string& from, const string& to) : - _from(from), - _to(to) - { - } - - virtual void - transform(ostream& os, const DocumentInfo*, const string&, DOM_Node node) - { - if (node.isNull()) - { - throw SchemaViolation(__FILE__, __LINE__); - } - - DOM_Node child = node.getFirstChild(); - if (child.isNull() || child.getNodeType() != DOM_Node::TEXT_NODE) - { - throw SchemaViolation(__FILE__, __LINE__); - } - os << node; - } - - virtual ostream& - print(ostream& os) - { - os << "[validate float: from=" << _from << " to=" << _to << " ]"; - return os; - } - -private: - - string _from; - string _to; -}; - -class SequenceTransform : public Transform -{ -public: - - SequenceTransform(Transform* transform) : - _transform(transform) - { - } - - virtual void - transform(ostream& os, const DocumentInfo* info, const string&, DOM_Node node) - { - if (node.isNull()) - { - throw SchemaViolation(__FILE__, __LINE__); - } - string name = toString(node.getNodeName()); - os << "<" << name; - string length = getLengthAttribute(node); - os << " length=\"" << length << "\""; - // TODO: print attributes - os << ">"; - - long l = atol(length.c_str()); - - DOM_NodeList children = node.getChildNodes(); - for (unsigned int i = 0; i < children.getLength(); ++i) - { - DOM_Node child = children.item(i); - if (child.getNodeType() != DOM_Node::ELEMENT_NODE) - { - continue; - } - - static const string sequenceElementName = "e"; - string nodeName = toString(child.getNodeName()); - if (l == 0 || nodeName != sequenceElementName) - { - throw SchemaViolation(__FILE__, __LINE__); - } - _transform->transform(os, info, nodeName, child); - --l; - } - - os << "</" << name << ">"; - } - - virtual ostream& - print(ostream& os) - { - os << "[sequence]\n"; - os << "\telement:" << _transform->print(os); - os << "[sequence]\n"; - return os; - } - -private: - - Transform* _transform; -}; - -class StructTransform : public Transform -{ -public: - - StructTransform() - { - } - - virtual void - transform(ostream& os, const DocumentInfo* info, const string&, DOM_Node node) - { - if (node.isNull()) - { - throw SchemaViolation(__FILE__, __LINE__); - } - string name = toString(node.getNodeName()); - os << "<" << name; - // TODO: print attributes - os << ">"; - - DOM_NodeList children = node.getChildNodes(); - for (vector<ElementTransform*>::const_iterator p = _transforms.begin(); p != _transforms.end(); ++p) - { - DOM_Node child = findChild(node, (*p)->namespaceURI(), (*p)->name()); - (*p)->transform(os, info, (*p)->name(), child); - } - - os << "</" << name << ">"; - } - - virtual ostream& - print(ostream& os) - { - os << "[struct start]\n"; - for (unsigned int i = 0; i < _transforms.size(); ++i) - { - os << "\t"; - _transforms[i]->print(os); - os << "\n"; - } - os << "[struct end]\n"; - return os; - } - - void - append(ElementTransform* transform) - { - _transforms.push_back(transform); - } - -private: - - vector<ElementTransform*> _transforms; -}; - -class DefaultInitializedStructTransform : public Transform -{ -public: - - DefaultInitializedStructTransform() - { - } - - virtual void - transform(ostream& os, const DocumentInfo* info, const string& name, DOM_Node node) - { - os << "<" << name; - // TODO: print attributes - os << ">"; - - DOM_Node child; // Nil - - for (vector<ElementTransform*>::const_iterator p = _transforms.begin(); p != _transforms.end(); ++p) - { - (*p)->transform(os, info, (*p)->name(), child); - } - - os << "</" << name << ">"; - } - - virtual ostream& - print(ostream& os) - { - os << "[empty struct start]\n"; - for (unsigned int i = 0; i < _transforms.size(); ++i) - { - os << "\t"; - _transforms[i]->print(os); - os << "\n"; - } - os << "[struct end]\n"; - return os; - } - - void - append(ElementTransform* transform) - { - _transforms.push_back(transform); - } - -private: - - vector<ElementTransform*> _transforms; -}; - -class ClassTransform : public Transform -{ -public: - - ClassTransform(TransformMap& transforms) : - _transforms(transforms) - { - } - - virtual void - transform(ostream& os, const DocumentInfo* info, const string& name, DOM_Node node) - { - static const string xsitypeAttrName = "xsi:type"; - string type = getAttributeByName(node, xsitypeAttrName); - if (type.empty()) - { - static const string xsinilAttrName = "xsi:nil"; - string nil = getAttributeByName(node, xsinilAttrName); - if (nil.empty()) - { - throw SchemaViolation(__FILE__, __LINE__); - } - // - // Act as NilTransform - // - os << node; - return; - } - - string n = convertQName(type, info); - - // - // Technically this is only permitted to be a more derived - // type - however, this will not be enforced here. - // - TransformMap::const_iterator p = _transforms.find(n); - if (p == _transforms.end()) - { - cout << n << endl; - throw SchemaViolation(__FILE__, __LINE__); - } - p->second->transform(os, info, name, node); - } - - virtual ostream& - print(ostream& os) - { - os << "[class]\n"; - return os; - } - -private: - - TransformMap& _transforms; - -}; - -class EmitStringTransform : public Transform -{ -public: - - EmitStringTransform(const string& s) : - _s(s) - { - } - - virtual void - transform(ostream& os, const DocumentInfo*, const string& name, DOM_Node) - { - if (!_s.empty()) - { - os << "<" << name << ">" << _s << "</" << name << ">"; - } - else - { - os << "<" << name << "/>"; - } - } - - virtual ostream& - print(ostream& os) - { - os << "[emit string: \"" << _s << "\"]"; - return os; - } - -private: - - string _s; -}; - -class EmitAttributeTransform : public Transform -{ -public: - - EmitAttributeTransform(const string& s) : - _s(s) - { - } - - virtual void - transform(ostream& os, const DocumentInfo*, const string& name, DOM_Node) - { - os << "<" << name << " " << _s << "/>"; - } - - virtual ostream& - print(ostream& os) - { - os << "[emit attribute: \"" << _s << "\"]"; - return os; - } - -private: - - string _s; - -}; - -// -// TODO: all the references are dangerous (DOM_Node&). Should either -// be const DOM_Node& or DOM_Node. -// -class TransformFactory -{ -public: - - TransformFactory(DOM_Document&, DOM_Document&, TransformMap&, TransformMap&); - ~TransformFactory(); - - enum Type - { - TypeInteger, // byte, short, int, long - TypeFloat, // float, double - TypeString, - TypeEnumeration, - TypeStruct, - TypeClass, - TypeException, - TypeDictionary, - TypeDictionaryContent, - TypeSequence, - TypeProxy, - TypeReference, - TypeInternal - }; - -private: - - DOM_Node findTypeInDocument(DOM_Document& doc, const ::std::string& local); - void findType(const DocumentMap&, const DocumentInfo*, const ::std::string&, DOM_Node&, DocumentInfo*&); - - Transform* createTransform(const DocumentInfo*, DOM_Node&, Type, const ::std::string&, - const DocumentInfo*, DOM_Node&, Type, const ::std::string&); - - Transform* createTransformByTypeName(const DocumentInfo*, const ::std::string&, - const DocumentInfo*, const ::std::string&); - - Transform* createComplexTypeTransform(DOM_Node&, DOM_Node&); - Transform* createSimpleTypeTransform(DOM_Node&, DOM_Node&); - - Transform* createStructTransform(const DocumentInfo*, DOM_Node&, const DocumentInfo*, DOM_Node&); - Transform* createStaticClassTransform(DOM_Node&, DOM_Node&); - Transform* createClassTransform(const DocumentInfo*, DOM_Node&, const DocumentInfo*, DOM_Node&); - Transform* createSequenceTransform(const DocumentInfo*, DOM_Node&, const DocumentInfo*, DOM_Node&); - Transform* createDictionaryTransform(const DocumentInfo*, DOM_Node&, const DocumentInfo*, DOM_Node&); - void createEnumValues(DOM_Node&, ::std::vector< ::std::string>&); - Transform* createEnumerationTransform(DOM_Node&); - - void createSequenceElementTransform(const DocumentInfo*, DOM_Node&, const DocumentInfo*, DOM_Node&, - ::std::vector<ElementTransform*>&); - void createClassContentTransform(const DocumentInfo*, DOM_Node&, - const DocumentInfo*, DOM_Node&, - ::std::vector<ElementTransform*>&); - - Transform* createDefaultInitializedStructTransform(const DocumentInfo*, DOM_Node&); - void createDefaultInitializedSequenceElementTransform(const DocumentInfo*, - DOM_Node&, ::std::vector<ElementTransform*>&); - Transform* createDefaultInitializedTransform(const DocumentInfo*, const ::std::string&); - - Type getType(DOM_Node&); - Type getTypeByName(const DocumentMap&, const DocumentInfo*, const ::std::string&, DOM_Node&, DocumentInfo*&); - - DOM_Node findSchemaRoot(const DOM_Document&); - - void import(DocumentMap&, const ::std::string&, const ::std::string&); - void processImport(DOM_Document&, DocumentMap&); - - void processElements(const DocumentInfo* info); - - // - // Set of documents. The set of all documents is the entire - // document set. - // - // The map maps from targetNamespace to DocumentInfo. - // - DocumentMap _fromDocs; - DocumentMap _toDocs; - - // - // Map of local@uri element names to transforms. Needed for actual - // transform. - // - TransformMap& _elements; - - // - // Map of local@uri type names to transform. This information - // cached for creation of the transform. - // - TransformMap _types; - - // - // Map of local@uri class transforms (based on static type). This - // information cached for creation of the transform. - // - TransformMap& _staticClassTransforms; - - // - // Map of local@uri transforms for creating new types. This - // information cached for creation of the transform. - // - TransformMap _defaultInitializedTransforms; -}; - -TransformFactory::TransformFactory(DOM_Document& fromDoc, DOM_Document& toDoc, - TransformMap& elements, - TransformMap& staticClassTransforms) : - _elements(elements), - _staticClassTransforms(staticClassTransforms) -{ - DocumentInfo* fromInfo = new DocumentInfo(); - fromInfo->document = fromDoc; - - DocumentInfo* toInfo = new DocumentInfo(); - toInfo->document = toDoc; - - DOM_Node fromSchema = findSchemaRoot(fromDoc); - assert(!fromSchema.isNull()); - - DOM_Node toSchema = findSchemaRoot(toDoc); - assert(!toSchema.isNull()); - - // - // Create the namespace maps for the two schemas. - // - createNSMap(fromInfo, fromSchema); - createNSMap(toInfo, toSchema); - - // - // Add the root document to the document map. - // - _fromDocs.insert(make_pair(fromInfo->targetNamespace, fromInfo)); - _toDocs.insert(make_pair(toInfo->targetNamespace, toInfo)); - - processImport(fromDoc, _fromDocs); - processImport(toDoc, _toDocs); - - for (DocumentMap::const_iterator p = _fromDocs.begin(); p != _fromDocs.end(); ++p) - { - processElements(p->second); - } -} - -TransformFactory::~TransformFactory() -{ -} - -struct StringTypeTable -{ - string name; - TransformFactory::Type type; - - bool operator==(const string& rhs) const { return name == rhs; } -}; - -TransformFactory::Type -TransformFactory::getType(DOM_Node& node) -{ - // - // Check the appinfo element for the actual type. - // - static const StringTypeTable items[] = - { - { "enumeration", TypeEnumeration }, - { "struct", TypeStruct }, - { "class", TypeClass }, - { "exception", TypeException }, - { "dictionary", TypeDictionary }, - { "dictionaryContent", TypeDictionaryContent }, - { "sequence", TypeSequence }, - { "proxy", TypeProxy }, - { "reference", TypeReference }, - { "internal", TypeInternal } - }; - static const StringTypeTable* begin = &items[0]; - static const StringTypeTable* end = &items[sizeof(items)/sizeof(items[0])]; - - string type = findAppinfoType(node); - - const StringTypeTable* p = find(begin, end, type); - if (p == end) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - return p->type; -} - -TransformFactory::Type -TransformFactory::getTypeByName(const DocumentMap& docs, const DocumentInfo* info, const string& type, - DOM_Node& n, DocumentInfo*& nInfo) -{ - // - // First check to see if the type is a primitive schema type. - // - static const StringTypeTable items[] = - { - { "xs:byte", TypeInteger }, - { "xs:short", TypeInteger }, - { "xs:int", TypeInteger }, - { "xs:long", TypeInteger }, - { "xs:float", TypeFloat }, - { "xs:double", TypeFloat }, - { "xs:string", TypeString }, - }; - static const StringTypeTable* begin = &items[0]; - static const StringTypeTable* end = &items[sizeof(items)/sizeof(items[0])]; - - const StringTypeTable* p = find(begin, end, type); - if (p != end) - { - return p->type; - } - - findType(docs, info, type, n, nInfo); - if (n.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - return getType(n); -} - -Transform* -TransformFactory::createTransformByTypeName(const DocumentInfo* fromTypeInfo, const string& fromTypeName, - const DocumentInfo* toTypeInfo, const string& toTypeName) -{ - DOM_Node from; - DocumentInfo* fromInfo; - Type fromType = getTypeByName(_fromDocs, fromTypeInfo, fromTypeName, from, fromInfo); - - DOM_Node to; - DocumentInfo* toInfo; - Type toType = getTypeByName(_toDocs, toTypeInfo, toTypeName, to, toInfo); - - return createTransform(fromInfo, from, fromType, fromTypeName, toInfo, to, toType, toTypeName); -} - -// -// This really needs to do more or less depending on the type of -// transform (element, or dealing with complexType/simpleType. -// -Transform* -TransformFactory::createTransform(const DocumentInfo* fromInfo, DOM_Node& from, - Type fromType, const string& fromTypeName, - const DocumentInfo* toInfo, DOM_Node& to, - Type toType, const string& toTypeName) -{ - - TransformMap::const_iterator p = _types.find(fromTypeName); - if (p != _types.end()) - { - //cout << "returning previously cached transform: " << fromTypeName << endl; - return p->second; - } - - Transform* transform = 0; - - // - // First handle transforms where the types are equivalent. - // - if (fromType == toType) - { - switch(fromType) - { - case TypeInteger: - { - transform = new ValidateIntegerTransform(fromTypeName, toTypeName); - break; - } - - case TypeFloat: - { - transform = new ValidateFloatTransform(fromTypeName, toTypeName); - break; - } - - case TypeString: - case TypeProxy: // Same as string - case TypeReference: // Same as string - { - transform = new NilTransform(); - break; - } - - case TypeEnumeration: - { - // - // If the type names are not the same then it's illegal. - // - // TODO: This doesn't allow the renaming of types. By - // removing this comparison renaming of types would be - // permitted. Should this be permitted? - // - if (fromTypeName != toTypeName) - { - throw IllegalTransform(__FILE__, __LINE__); - } - - transform = createEnumerationTransform(to); - break; - } - - case TypeStruct: - { - // - // If the type names are not the same then it's illegal. - // - // TODO: This doesn't allow the renaming of types. By - // removing this comparison renaming of types would be - // permitted. Should this be permitted? - // - if (fromTypeName != toTypeName) - { - throw IllegalTransform(__FILE__, __LINE__); - } - - transform = createStructTransform(fromInfo, from, toInfo, to); - break; - } - - case TypeDictionaryContent: - { - // - // If the type names are not the same then it's illegal. - // - // TODO: This doesn't allow the renaming of types. By - // removing this comparison renaming of types would be - // permitted. Should this be permitted? - // - if (fromTypeName != toTypeName) - { - throw IllegalTransform(__FILE__, __LINE__); - } - - transform = createStructTransform(fromInfo, from, toInfo, to); - break; - } - - case TypeDictionary: - { - // - // If the type names are not the same then it's illegal. - // - // TODO: This doesn't allow the renaming of types. By - // removing this comparison renaming of types would be - // permitted. Should this be permitted? - // - if (fromTypeName != toTypeName) - { - throw IllegalTransform(__FILE__, __LINE__); - } - - transform = createDictionaryTransform(fromInfo, from, toInfo, to); - break; - } - - case TypeSequence: - { - // - // If the type names are not the same then it's illegal. - // - // TODO: This doesn't allow the renaming of types. By - // removing this comparison renaming of types would be - // permitted. Should this be permitted? - // - if (fromTypeName != toTypeName) - { - throw IllegalTransform(__FILE__, __LINE__); - } - - transform = createSequenceTransform(fromInfo, from, toInfo, to); - break; - } - - case TypeClass: - { - // - // If the type names are not the same then it's illegal. - // - // TODO: This doesn't allow the renaming of types. By - // removing this comparison renaming of types would be - // permitted. Should this be permitted? - // - if (fromTypeName != toTypeName) - { - throw IllegalTransform(__FILE__, __LINE__); - } - - Transform* staticTransform = createClassTransform(fromInfo, from, toInfo, to); - return new ClassTransform(_staticClassTransforms); - break; - } - - case TypeInternal: - { - // - // No transformation created for internal stuff. - // - transform = new InternalTransform(); - break; - } - - case TypeException: - default: - throw IllegalTransform(__FILE__, __LINE__); - } - } - - if (transform == 0) - { - // - // Next we have transforms from type-to-type. - // - if (fromType == TypeString && toType == TypeEnumeration) - { - // - // String to enumeration transform needs to validate the - // string as a member of the enumeration values. - // - transform = createEnumerationTransform(to); - } - else if (fromType == TypeEnumeration && toType == TypeString) - { - // - // Enumeration to string transform is nil transform. - // - transform = new NilTransform(); - } - } - - // - // TODO: struct->class, class->struct. - // - - if (transform == 0) - { - throw IllegalTransform(__FILE__, __LINE__); - } - - _types.insert(make_pair(fromTypeName, transform)); - - return transform; -} - -Transform* -TransformFactory::createStructTransform(const DocumentInfo* fromInfo, DOM_Node& from, - const DocumentInfo* toInfo, DOM_Node& to) -{ - static const string sequenceName = "xs:sequence"; - - DOM_Node fromSeq = findChild(from, sequenceName); - DOM_Node toSeq = findChild(to, sequenceName); - if (fromSeq.isNull() || toSeq.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - StructTransform* nodeTransform = new StructTransform(); - - vector<ElementTransform*> v; - createSequenceElementTransform(fromInfo, fromSeq, toInfo, toSeq, v); - for(vector<ElementTransform*>::const_iterator p = v.begin(); p != v.end(); ++p) - { - nodeTransform->append(*p); - } - - return nodeTransform; -} - -void -TransformFactory::createSequenceElementTransform(const DocumentInfo* fromInfo, DOM_Node& from, - const DocumentInfo* toInfo, DOM_Node& to, - vector<ElementTransform*>& v) -{ - // - // Allowable transforms: - // - // * Node added. - // * Node removed. - // * Node moved. - // - - DOM_NodeList fromSeqChildren = from.getChildNodes(); - DOM_NodeList toSeqChildren = to.getChildNodes(); - - // - // First run through the to set. This loop handles the node - // remove, and node changed transforms (plus allowable type - // changes). - // - for (unsigned int i = 0; i < toSeqChildren.getLength(); ++i) - { - ElementTransform* transform = 0; - DOM_Node toChild = toSeqChildren.item(i); - if (toChild.getNodeType() != DOM_Node::ELEMENT_NODE) - { - continue; - } - - static const string element = "xs:element"; - if (toString(toChild.getNodeName()) != element) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - string toElementName = getNameAttribute(toChild); - string toTypeName = getTypeAttribute(toChild); - - // - // Search for the node in the fromSeqChildren list. - // - for (unsigned int j = 0; j < fromSeqChildren.getLength(); ++j) - { - DOM_Node fromChild = fromSeqChildren.item(j); - - if (fromChild.getNodeType() != DOM_Node::ELEMENT_NODE) - { - // Skip non element nodes. - continue; - } - - if (toString(fromChild.getNodeName()) != element) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - string fromElementName = getNameAttribute(fromChild); - - if (fromElementName == toElementName) - { - string fromTypeName = getTypeAttribute(fromChild); - Transform* t = createTransformByTypeName(fromInfo, fromTypeName, toInfo, toTypeName); - - transform = new ElementTransform(toInfo->targetNamespace, toElementName, t); - assert(transform); - } - } - - // - // If there is no transform then this is a new node - // type. Create a transform to add an empty element of the - // appropriate type. - // - if (!transform) - { - Transform* t = createDefaultInitializedTransform(toInfo, toTypeName); - transform = new ElementTransform(toInfo->targetNamespace, toElementName, t); - } - - v.push_back(transform); - } -} - -void -TransformFactory::createClassContentTransform(const DocumentInfo* fromInfo, DOM_Node& from, - const DocumentInfo* toInfo, DOM_Node& to, - vector<ElementTransform*>& v) -{ - static const string complexContentName = "xs:complexContent"; - static const string sequenceName = "xs:sequence"; - static const string extension = "xs:extension"; - static const string baseAttrName = "base"; - - DOM_Node fromContent = findChild(from, complexContentName); - DOM_Node toContent = findChild(to, complexContentName); - - if (fromContent.isNull() && toContent.isNull()) - { - // - // Must be base of a class heirarchy (while this - // implementation is a little more flexible, with Ice it is - // limited to ::Ice::Object). - // - - // - // Look for xs:sequence - // - DOM_Node fromSeq = findChild(from, sequenceName); - DOM_Node toSeq = findChild(from, sequenceName); - - if (fromSeq.isNull() || toSeq.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - // - // TODO: Create cache of base class transforms - // - createSequenceElementTransform(fromInfo, fromSeq, toInfo, toSeq, v); - return; - } - - if (fromContent.isNull() || toContent.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - DOM_Node fromExtension = findChild(fromContent, extension); - DOM_Node toExtension = findChild(toContent, extension); - - if (fromExtension.isNull() || toExtension.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - // TOOD: getAttributeBase? - string fromBaseName = getAttributeByName(fromExtension, baseAttrName); - string toBaseName = getAttributeByName(toExtension, baseAttrName); - - // - // Cannot change base class. - // - if (fromBaseName != toBaseName) - { - throw IllegalTransform(__FILE__, __LINE__); - } - - DOM_Node fromBaseNode; - DocumentInfo* fromBaseInfo; - findType(_fromDocs, fromInfo, fromBaseName, fromBaseNode, fromBaseInfo); - DOM_Node toBaseNode; - DocumentInfo* toBaseInfo; - findType(_toDocs, toInfo, toBaseName, toBaseNode, toBaseInfo); - - if (fromBaseNode.isNull() || toBaseNode.isNull()) - { - throw SchemaViolation(__FILE__, __LINE__); - } - - // - // Find the content transform for the base type. - // - createClassContentTransform(fromBaseInfo, fromBaseNode, toBaseInfo, toBaseNode, v); - - // - // Look for xs:sequence - // - DOM_Node fromSeq = findChild(fromExtension, sequenceName); - DOM_Node toSeq = findChild(toExtension, sequenceName); - - if (fromSeq.isNull() || toSeq.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - createSequenceElementTransform(fromInfo, fromSeq, toInfo, toSeq, v); -} - -// -// Schema for class looks like: -// -// <xs:complexContent> -// <xs:extension base=...> -// <xs:sequence> ... -// -Transform* -TransformFactory::createClassTransform(const DocumentInfo* fromInfo, DOM_Node& from, - const DocumentInfo* toInfo, DOM_Node& to) -{ - string type = getNameAttribute(to); - type += '@'; - type += toInfo->targetNamespace; - - TransformMap::const_iterator p = _staticClassTransforms.find(type); - if (p != _staticClassTransforms.end()) - { - cout << "returning cached static class transform: " << type << endl; - return p->second; - } - - vector<ElementTransform*> v; - createClassContentTransform(fromInfo, from, toInfo, to, v); - - StructTransform* nodeTransform = new StructTransform(); - for(vector<ElementTransform*>::const_iterator p = v.begin(); p != v.end(); ++p) - { - nodeTransform->append(*p); - } - - _staticClassTransforms.insert(make_pair(type, nodeTransform)); - - return nodeTransform; -} - -Transform* -TransformFactory::createSequenceTransform(const DocumentInfo* fromInfo, DOM_Node& from, - const DocumentInfo* toInfo, DOM_Node& to) -{ - static const string sequenceName = "xs:sequence"; - - DOM_Node fromSeq = findChild(from, sequenceName); - DOM_Node toSeq = findChild(to, sequenceName); - if (fromSeq.isNull() || toSeq.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - // - // Sequences have one element - which contains the type of the sequence. - // - static const string element = "xs:element"; - - DOM_Node fromElement = findChild(fromSeq, element); - DOM_Node toElement = findChild(toSeq, element); - - if (fromElement.isNull() || toElement.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - string fromTypeName = getTypeAttribute(fromElement); - string toTypeName = getTypeAttribute(toElement); - - Transform* transform = createTransformByTypeName(fromInfo, fromTypeName, toInfo, toTypeName); - return new SequenceTransform(transform); -} - -Transform* -TransformFactory::createDictionaryTransform(const DocumentInfo* fromInfo, DOM_Node& from, - const DocumentInfo* toInfo, DOM_Node& to) -{ - static const string sequenceName = "xs:sequence"; - - DOM_Node fromSeq = findChild(from, sequenceName); - DOM_Node toSeq = findChild(to, sequenceName); - if (fromSeq.isNull() || toSeq.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - // - // Sequences have one element - which contains the type of the sequence. - // - static const string element = "xs:element"; - - DOM_Node fromElement = findChild(fromSeq, element); - DOM_Node toElement = findChild(toSeq, element); - - if (fromElement.isNull() || toElement.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - string fromTypeName = getTypeAttribute(fromElement); - string toTypeName = getTypeAttribute(toElement); - - Transform* transform = createTransformByTypeName(fromInfo, fromTypeName, toInfo, toTypeName); - return new SequenceTransform(transform); -} - -void -TransformFactory::createEnumValues(DOM_Node& to, vector<string>& values) -{ - static const string restriction = "xs:restriction"; - - DOM_Node toRes = findChild(to, restriction); - if (toRes.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - // - // Gather up a list of allowable values. - // - DOM_NodeList toResChildren = toRes.getChildNodes(); - - for (unsigned int i = 0; i < toResChildren.getLength(); ++i) - { - DOM_Node toChild = toResChildren.item(i); - - if (toChild.getNodeType() != DOM_Node::ELEMENT_NODE) - { - continue; - } - - if (toString(toChild.getNodeName()) != "xs:enumeration") - { - throw InvalidSchema(__FILE__, __LINE__); - } - - string value = getValueAttribute(toChild); - if (value.empty()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - values.push_back(value); - } -} - -Transform* -TransformFactory::createEnumerationTransform(DOM_Node& to) -{ - vector<string> values; - createEnumValues(to, values); - - return new ValidateEnumerationTransform(values); -} - -void -TransformFactory::createDefaultInitializedSequenceElementTransform(const DocumentInfo* info, DOM_Node& node, - vector<ElementTransform*>& v) -{ - // - // Allowable transforms: - // - // * Node added. - // * Node removed. - // * Node moved. - // - - DOM_NodeList seqChild = node.getChildNodes(); - for (unsigned int i = 0; i < seqChild.getLength(); ++i) - { - DOM_Node child = seqChild.item(i); - if (child.getNodeType() != DOM_Node::ELEMENT_NODE) - { - continue; - } - - static const string element = "xs:element"; - if (toString(child.getNodeName()) != element) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - string elementName = getNameAttribute(child); - string typeName = getTypeAttribute(child); - - Transform* t = createDefaultInitializedTransform(info, typeName); - ElementTransform* transform = new ElementTransform(info->targetNamespace, elementName, t); - - v.push_back(transform); - } -} - -Transform* -TransformFactory::createDefaultInitializedStructTransform(const DocumentInfo* info, DOM_Node& node) -{ - static const string sequenceName = "xs:sequence"; - - DOM_Node seq = findChild(node, sequenceName); - if (seq.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - DefaultInitializedStructTransform* transform = new DefaultInitializedStructTransform(); - - vector<ElementTransform*> v; - createDefaultInitializedSequenceElementTransform(info, seq, v); - for(vector<ElementTransform*>::const_iterator p = v.begin(); p != v.end(); ++p) - { - transform->append(*p); - } - - return transform; -} - -Transform* -TransformFactory::createDefaultInitializedTransform(const DocumentInfo* info, const string& typeName) -{ - string fullTypeName = convertQName(typeName, info); - TransformMap::const_iterator p = _defaultInitializedTransforms.find(fullTypeName); - if (p != _defaultInitializedTransforms.end()) - { - // - // Return cached empty transform. - // - return p->second; - } - - DOM_Node n; - DocumentInfo* nInfo; - Type type = getTypeByName(_toDocs, info, typeName, n, nInfo); - - Transform* transform = 0; - switch(type) - { - case TypeInteger: - transform = new EmitStringTransform("0"); - break; - - case TypeFloat: - transform = new EmitStringTransform("0.0"); - break; - - case TypeProxy: - case TypeReference: - case TypeString: - // - // Default string, reference & proxy is empty. - // - transform = new EmitStringTransform(""); - break; - - case TypeEnumeration: - { - vector<string> values; - createEnumValues(n, values); - transform = new EmitStringTransform(values[0]); - break; - } - - case TypeStruct: - { - if (n.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - transform = createDefaultInitializedStructTransform(info, n); - break; - } - - case TypeDictionary: - case TypeSequence: - { - if (n.isNull()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - transform = new EmitAttributeTransform("length=\"0\""); - break; - } - - case TypeInternal: - case TypeException: - case TypeDictionaryContent: - case TypeClass: - default: - throw IllegalTransform(__FILE__, __LINE__); - } - - if (transform == 0) - { - throw IllegalTransform(__FILE__, __LINE__); - } - - _defaultInitializedTransforms.insert(make_pair(fullTypeName, transform)); - - return transform; -} - -void -print(DOM_Node& node, unsigned int level) -{ - if (node.isNull()) - { - return; - } - unsigned int i; - for (i = 0; i < level; ++i) - { - cout << " "; - } - ++level; - cout << toString(node.getNodeName()) << endl; - - DOM_NodeList children = node.getChildNodes(); - - for (i = 0; i < children.getLength(); ++i) - { - for (unsigned int l = 0; l < level; ++l) - { - cout << " "; - } - DOM_Node child = children.item(i); - print(child, level); - } -} - -DOM_Node -TransformFactory::findTypeInDocument(DOM_Document& doc, const string& local) -{ - DOM_Node schema = findSchemaRoot(doc); - - DOM_NodeList children = schema.getChildNodes(); - unsigned int i; - for (i = 0; i < children.getLength(); ++i) - { - DOM_Node child = children.item(i); - if (child.getNodeType() == DOM_Node::ELEMENT_NODE) - { - string na = getNameAttribute(child); - if (na == local) - { - return child; - } - } - } - - return DOM_Node(); -} - -// -// This find method takes the type QName and then maps the prefix -// portion to a namespace in the current document (info). Next the -// documents which have the given targetNamespace are searched for an -// element node with that name. -// -void -TransformFactory::findType(const DocumentMap& docs, const DocumentInfo* info, const string& type, - DOM_Node& n, DocumentInfo*& nInfo) -{ - string uri; - string local; - - size_t pos = type.find(':'); - if (pos != string::npos) - { - string prefix = type.substr(0, pos); - PrefixURIMap::const_iterator p = info->nsMap.find(prefix); - if (p == info->nsMap.end()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - uri = p->second; - local = type.substr(pos+1); - - //cout << "looking for : " << local << " @ " << uri << endl; - } - else - { - uri = info->targetNamespace; - local = type; - - //cout << "looking for : " << local << " @ " << uri << endl; - } - - // - // Find all documents with targetNamespace == uri - // - // TODO: multimap - // - DocumentMap::const_iterator p = docs.find(uri); - if (p != docs.end()) - { - n = findTypeInDocument(p->second->document, local); - nInfo = p->second; - } -} - -DOM_Node -TransformFactory::findSchemaRoot(const DOM_Document& root) -{ - // - // TODO: Can this be static const? - // - DOMString schemaURI("http://www.w3.org/2001/XMLSchema"); - DOMString schemaLocalName("schema"); - DOM_Node n; - - DOM_NodeList nodes = root.getElementsByTagNameNS(schemaURI, schemaLocalName); - if (nodes.getLength() != 1) - { - throw InvalidSchema(__FILE__, __LINE__); - } - return nodes.item(0); -} - -void -TransformFactory::import(DocumentMap& documents, const string& ns, const string& loc) -{ - DOMTreeErrorReporter errorReporter; - DOMParser parser; - parser.setValidationScheme(DOMParser::Val_Never); - parser.setDoNamespaces(true); - parser.setErrorHandler(&errorReporter); - // Entity resolver? - - try - { - parser.parse(loc.c_str()); - if (errorReporter.getSawErrors()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - } - catch (const XMLException& toCatch) - { - cout << "Exception message is: \n" - << DOMString(toCatch.getMessage()) << "\n" ; - throw InvalidSchema(__FILE__, __LINE__); - } - catch (const SAXParseException& toCatch) - { - cout << "Exception message is: \n" - << DOMString(toCatch.getMessage()) << "\n" ; - throw InvalidSchema(__FILE__, __LINE__); - } - catch (...) - { - cout << "Unexpected Exception \n" ; - throw InvalidSchema(__FILE__, __LINE__); - } - DOM_Document document = parser.getDocument(); - - DOM_Node schema = findSchemaRoot(document); - - DocumentInfo* info = new DocumentInfo(); - info->document = document; - - createNSMap(info, schema); - - // - // Rename the targetNamespace: - // - info->targetNamespace = ns; - - documents.insert(make_pair(info->targetNamespace, info)); - - // - // Process any imports in the imported document. - // - processImport(document, documents); -} - -void -TransformFactory::processImport(DOM_Document& parent, DocumentMap& documents) -{ - DOM_Node schema = findSchemaRoot(parent); - assert(!schema.isNull()); - - DOM_Node child = schema.getFirstChild(); - while (!child.isNull()) - { - static const string importName = "xs:import"; - string nodeName = toString(child.getNodeName()); - if (nodeName == importName) - { - string ns = getAttributeByName(child, "namespace"); - string loc = getAttributeByName(child, "schemaLocation"); - - import(documents, ns, loc); - } - child = child.getNextSibling(); - } -} - -void -TransformFactory::processElements(const DocumentInfo* info) -{ - DOM_Node schema = findSchemaRoot(info->document); - - DOM_NodeList children = schema.getChildNodes(); - unsigned int i; - for (i = 0; i < children.getLength(); ++i) - { - DOM_Node child = children.item(i); - if (child.getNodeType() != DOM_Node::ELEMENT_NODE) - { - continue; - } - string nodeName = toString(child.getNodeName()); - - static const string element = "xs:element"; - - if (nodeName != element) - { - continue; - } - - string nameAttr = getNameAttribute(child); - - DOM_Node to; - DocumentInfo* toNodeInfo; // Overrides the top-level toInfo. - - // - // In this case info is correct since the element name must be - // an unqualified name. - // - assert(nameAttr.find(':') == string::npos); - - findType(_toDocs, info, nameAttr, to, toNodeInfo); - if (to.isNull()) - { - cout << "ignoring " << nameAttr << endl; - // - // No equivalent in the new schema. - // - continue; - } - - string toNodeName = toString(to.getNodeName()); - string toNameAttr = getNameAttribute(to); - - // - // Sanity check. - // - assert(toNameAttr == nameAttr); - - // - // Construct the full element name - local@uri - // - string fullElementName = nameAttr; - fullElementName += '@'; - fullElementName += info->targetNamespace; - - if (_elements.find(fullElementName) != _elements.end()) - { - cout << "redefinition of element: " << fullElementName << endl; - throw InvalidSchema(__FILE__, __LINE__); - } - - string fromTypeName = getTypeAttribute(child); - string toTypeName = getTypeAttribute(to); - - // - // Ignore anonymous elements (operation contents). - // - if (fromTypeName.empty() && toTypeName.empty()) - { - continue; - } - - // - // However, it's not legal for an element to change - // type. - // - if (fromTypeName.empty() || toTypeName.empty()) - { - throw InvalidSchema(__FILE__, __LINE__); - } - - Transform* transform = createTransformByTypeName(info, fromTypeName, toNodeInfo, toTypeName); - //cout << "new element: " << fullElementName << endl; - - // - // Add association between name & transform - // - _elements.insert(make_pair(fullElementName, transform)); - } -} - - -Transformer::Transformer(DOM_Document& fromDoc, DOM_Document& toDoc) -{ - TransformFactory factory(fromDoc, toDoc, _elements, _staticClassTransforms); -} - -Transformer::~Transformer() -{ -} - -void -Transformer::transform(ostream& os, DOM_Document& doc) -{ - DOM_Node root = doc.getFirstChild(); - DocumentInfo info; - info.document = doc; - createNSMap(&info, root); - - DOM_NodeList children = root.getChildNodes(); - for (unsigned int i = 0; i < children.getLength(); ++i) - { - DOM_Node child = children.item(i); - if (child.getNodeType() != DOM_Node::ELEMENT_NODE) - { - continue; - } - - string nodeName = toString(child.getNodeName()); - - // - // Create local@namespace version of the element name. - // - string n = convertQName(nodeName, &info); - - //cout << "looking for : " << n << endl; - - TransformMap::const_iterator p = _elements.find(n); - if (p == _elements.end()) - { - cerr << "cannot find element: " << n << endl; - throw SchemaViolation(__FILE__, __LINE__); - } - - p->second->transform(os, &info, nodeName, child); - } -} - |