summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
authorMatthew Newhook <matthew@zeroc.com>2002-02-14 01:56:06 +0000
committerMatthew Newhook <matthew@zeroc.com>2002-02-14 01:56:06 +0000
commita8511e4b58199bbc2602c28cccfbe09215218f53 (patch)
tree980debb574cf0d8f298d8a226c683073c330fdcd /cpp
parent... (diff)
downloadice-a8511e4b58199bbc2602c28cccfbe09215218f53.tar.bz2
ice-a8511e4b58199bbc2602c28cccfbe09215218f53.tar.xz
ice-a8511e4b58199bbc2602c28cccfbe09215218f53.zip
This code isn't ready to commit. However I'm going on vacation and don't
want to chance losing it.
Diffstat (limited to 'cpp')
-rw-r--r--cpp/include/Slice/XsdVisitor.h56
-rw-r--r--cpp/src/Freeze/ErrorHandler.h56
-rw-r--r--cpp/src/Freeze/Print.cpp420
-rw-r--r--cpp/src/Freeze/Print.h14
-rw-r--r--cpp/src/Freeze/Test.cpp129
-rw-r--r--cpp/src/Freeze/Transform.cpp2047
-rw-r--r--cpp/src/Freeze/Transform.h132
-rw-r--r--cpp/src/Slice/XsdVisitor.cpp518
8 files changed, 3372 insertions, 0 deletions
diff --git a/cpp/include/Slice/XsdVisitor.h b/cpp/include/Slice/XsdVisitor.h
new file mode 100644
index 00000000000..aeba207028e
--- /dev/null
+++ b/cpp/include/Slice/XsdVisitor.h
@@ -0,0 +1,56 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+#ifndef SLICE_XSD_VISITOR_H
+#define SLICE_XSD_VISITOR_H
+
+#include <Slice/Parser.h>
+#include <IceUtil/OutputUtil.h>
+#include <stack>
+
+namespace Slice
+{
+
+class XsdVisitor : public ::IceUtil::noncopyable, public ParserVisitor
+{
+public:
+
+ XsdVisitor();
+ XsdVisitor(::std::ostream&);
+
+ void emitElements(bool);
+
+ virtual bool visitClassDefStart(const ClassDefPtr&);
+ virtual bool visitExceptionStart(const ExceptionPtr&);
+ virtual bool visitStructStart(const StructPtr&);
+ virtual void visitOperation(const OperationPtr&);
+ virtual void visitEnum(const EnumPtr&);
+ virtual void visitSequence(const SequencePtr&);
+ virtual void visitDictionary(const DictionaryPtr&);
+
+private:
+
+ void annotate(const ::std::string&);
+ void emitElement(const DataMemberPtr&);
+ void emitElement(const TypeString&);
+
+ std::string containedToId(const ContainedPtr&);
+
+protected:
+
+ std::string toString(const SyntaxTreeBasePtr&);
+
+ ::IceUtil::XMLOutput O;
+ bool _emitElements;
+};
+
+}
+
+#endif
diff --git a/cpp/src/Freeze/ErrorHandler.h b/cpp/src/Freeze/ErrorHandler.h
new file mode 100644
index 00000000000..5f169670029
--- /dev/null
+++ b/cpp/src/Freeze/ErrorHandler.h
@@ -0,0 +1,56 @@
+#ifndef ERROR_HANDLER_H
+#define ERROR_HANDLER_H
+
+#include <sax/ErrorHandler.hpp>
+#include <sax/SAXParseException.hpp>
+
+#include <Freeze/Print.h>
+
+class DOMTreeErrorReporter : public ErrorHandler
+{
+public:
+ DOMTreeErrorReporter() :
+ _sawErrors(false)
+ {
+ }
+
+ void
+ warning(const SAXParseException& toCatch)
+ {
+ ::std::cerr << "Warning at file \"" << DOMString(toCatch.getSystemId())
+ << "\", line " << toCatch.getLineNumber()
+ << ", column " << toCatch.getColumnNumber()
+ << "\n Message: " << DOMString(toCatch.getMessage()) << ::std::endl;
+ }
+
+ void
+ error(const SAXParseException& toCatch)
+ {
+ _sawErrors = true;
+ ::std::cerr << "Error at file \"" << DOMString(toCatch.getSystemId())
+ << "\", line " << toCatch.getLineNumber()
+ << ", column " << toCatch.getColumnNumber()
+ << "\n Message: " << DOMString(toCatch.getMessage()) << ::std::endl;
+
+ }
+
+ void
+ fatalError(const SAXParseException& toCatch)
+ {
+ _sawErrors = true;
+ ::std::cerr << "Fatal at file \"" << DOMString(toCatch.getSystemId())
+ << "\", line " << toCatch.getLineNumber()
+ << ", column " << toCatch.getColumnNumber()
+ << "\n Message: " << DOMString(toCatch.getMessage()) << ::std::endl;
+ }
+
+ void resetErrors()
+ {
+ }
+
+ bool getSawErrors() const { return _sawErrors; }
+
+ bool _sawErrors;
+};
+
+#endif
diff --git a/cpp/src/Freeze/Print.cpp b/cpp/src/Freeze/Print.cpp
new file mode 100644
index 00000000000..2fedd9101d7
--- /dev/null
+++ b/cpp/src/Freeze/Print.cpp
@@ -0,0 +1,420 @@
+#include <util/PlatformUtils.hpp>
+#include <util/XMLString.hpp>
+#include <util/XMLUniDefs.hpp>
+#include <framework/XMLFormatter.hpp>
+#include <util/TranscodingException.hpp>
+
+#include <dom/DOMString.hpp>
+
+#include <dom/DOM.hpp>
+#include <parsers/DOMParser.hpp>
+
+#include <sax/ErrorHandler.hpp>
+#include <sax/SAXParseException.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <Freeze/Print.h>
+
+using namespace std;
+
+static XMLFormatter* gFormatter = 0;
+static XMLFormatter::UnRepFlags gUnRepFlags = XMLFormatter::UnRep_CharRef;
+static XMLCh* gEncodingName = 0;
+
+// ---------------------------------------------------------------------------
+// Local const data
+//
+// Note: This is the 'safe' way to do these strings. If you compiler supports
+// L"" style strings, and portability is not a concern, you can use
+// those types constants directly.
+// ---------------------------------------------------------------------------
+static const XMLCh gEndElement[] = { chOpenAngle, chForwardSlash, chNull };
+static const XMLCh gEndPI[] = { chQuestion, chCloseAngle, chNull};
+static const XMLCh gStartPI[] = { chOpenAngle, chQuestion, chNull };
+static const XMLCh gXMLDecl1[] =
+{
+ chOpenAngle, chQuestion, chLatin_x, chLatin_m, chLatin_l
+ , chSpace, chLatin_v, chLatin_e, chLatin_r, chLatin_s, chLatin_i
+ , chLatin_o, chLatin_n, chEqual, chDoubleQuote, chNull
+};
+static const XMLCh gXMLDecl2[] =
+{
+ chDoubleQuote, chSpace, chLatin_e, chLatin_n, chLatin_c
+ , chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chEqual
+ , chDoubleQuote, chNull
+};
+static const XMLCh gXMLDecl3[] =
+{
+ chDoubleQuote, chSpace, chLatin_s, chLatin_t, chLatin_a
+ , chLatin_n, chLatin_d, chLatin_a, chLatin_l, chLatin_o
+ , chLatin_n, chLatin_e, chEqual, chDoubleQuote, chNull
+};
+static const XMLCh gXMLDecl4[] =
+{
+ chDoubleQuote, chQuestion, chCloseAngle
+ , chLF, chNull
+};
+
+static const XMLCh gStartCDATA[] =
+{
+ chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D,
+ chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull
+};
+
+static const XMLCh gEndCDATA[] =
+{
+ chCloseSquare, chCloseSquare, chCloseAngle, chNull
+};
+static const XMLCh gStartComment[] =
+{
+ chOpenAngle, chBang, chDash, chDash, chNull
+};
+
+static const XMLCh gEndComment[] =
+{
+ chDash, chDash, chCloseAngle, chNull
+};
+
+static const XMLCh gStartDoctype[] =
+{
+ chOpenAngle, chBang, chLatin_D, chLatin_O, chLatin_C, chLatin_T,
+ chLatin_Y, chLatin_P, chLatin_E, chSpace, chNull
+};
+static const XMLCh gPublic[] =
+{
+ chLatin_P, chLatin_U, chLatin_B, chLatin_L, chLatin_I,
+ chLatin_C, chSpace, chDoubleQuote, chNull
+};
+static const XMLCh gSystem[] =
+{
+ chLatin_S, chLatin_Y, chLatin_S, chLatin_T, chLatin_E,
+ chLatin_M, chSpace, chDoubleQuote, chNull
+};
+static const XMLCh gStartEntity[] =
+{
+ chOpenAngle, chBang, chLatin_E, chLatin_N, chLatin_T, chLatin_I,
+ chLatin_T, chLatin_Y, chSpace, chNull
+};
+static const XMLCh gNotation[] =
+{
+ chLatin_N, chLatin_D, chLatin_A, chLatin_T, chLatin_A,
+ chSpace, chDoubleQuote, chNull
+};
+
+class DOMPrintFormatTarget : public XMLFormatTarget
+{
+public:
+ DOMPrintFormatTarget() {};
+ ~DOMPrintFormatTarget() {};
+
+ // -----------------------------------------------------------------------
+ // Implementations of the format target interface
+ // -----------------------------------------------------------------------
+
+ void writeChars(const XMLByte* const toWrite,
+ const unsigned int count,
+ XMLFormatter * const formatter)
+ {
+ // Surprisingly, Solaris was the only platform on which
+ // required the char* cast to print out the string correctly.
+ // Without the cast, it was printing the pointer value in hex.
+ // Quite annoying, considering every other platform printed
+ // the string with the explicit cast to char* below.
+ cout.write((char *) toWrite, (int) count);
+ };
+
+private:
+ // -----------------------------------------------------------------------
+ // Unimplemented methods.
+ // -----------------------------------------------------------------------
+ DOMPrintFormatTarget(const DOMPrintFormatTarget& other);
+ void operator=(const DOMPrintFormatTarget& rhs);
+};
+
+
+void
+printinit()
+{
+ gEncodingName = XMLString::transcode("UTF-8");
+
+ DOMPrintFormatTarget* formatTarget = new DOMPrintFormatTarget();
+ gFormatter = new XMLFormatter(gEncodingName, formatTarget,
+ XMLFormatter::NoEscapes, gUnRepFlags);
+
+}
+
+ostream& operator<< (ostream& target, const DOMString& s)
+{
+ char *p = s.transcode();
+ target << p;
+ delete [] p;
+ return target;
+}
+
+
+XMLFormatter& operator<< (XMLFormatter& strm, const DOMString& s)
+{
+ unsigned int lent = s.length();
+
+ if (lent <= 0)
+ return strm;
+
+ XMLCh* buf = new XMLCh[lent + 1];
+ XMLString::copyNString(buf, s.rawBuffer(), lent);
+ buf[lent] = 0;
+ strm << buf;
+ delete [] buf;
+ return strm;
+}
+
+
+// ---------------------------------------------------------------------------
+// ostream << DOM_Node
+//
+// Stream out a DOM node, and, recursively, all of its children. This
+// function is the heart of writing a DOM tree out as XML source. Give it
+// a document node and it will do the whole thing.
+// ---------------------------------------------------------------------------
+ostream& operator<<(ostream& target, DOM_Node& toWrite)
+{
+ // Get the name and value out for convenience
+ DOMString nodeName = toWrite.getNodeName();
+ DOMString nodeValue = toWrite.getNodeValue();
+ unsigned long lent = nodeValue.length();
+
+ switch (toWrite.getNodeType())
+ {
+ case DOM_Node::TEXT_NODE:
+ {
+ gFormatter->formatBuf(nodeValue.rawBuffer(),
+ lent, XMLFormatter::CharEscapes);
+ break;
+ }
+
+
+ case DOM_Node::PROCESSING_INSTRUCTION_NODE :
+ {
+ *gFormatter << XMLFormatter::NoEscapes << gStartPI << nodeName;
+ if (lent > 0)
+ {
+ *gFormatter << chSpace << nodeValue;
+ }
+ *gFormatter << XMLFormatter::NoEscapes << gEndPI;
+ break;
+ }
+
+
+ case DOM_Node::DOCUMENT_NODE :
+ {
+
+ DOM_Node child = toWrite.getFirstChild();
+ while( child != 0)
+ {
+ target << child;
+ // add linefeed in requested output encoding
+ *gFormatter << chLF;
+ target << flush;
+ child = child.getNextSibling();
+ }
+ break;
+ }
+
+
+ case DOM_Node::ELEMENT_NODE :
+ {
+ // The name has to be representable without any escapes
+ *gFormatter << XMLFormatter::NoEscapes
+ << chOpenAngle << nodeName;
+
+ // Output the element start tag.
+
+ // Output any attributes on this element
+ DOM_NamedNodeMap attributes = toWrite.getAttributes();
+ int attrCount = attributes.getLength();
+ for (int i = 0; i < attrCount; i++)
+ {
+ DOM_Node attribute = attributes.item(i);
+
+ //
+ // Again the name has to be completely representable. But the
+ // attribute can have refs and requires the attribute style
+ // escaping.
+ //
+ *gFormatter << XMLFormatter::NoEscapes
+ << chSpace << attribute.getNodeName()
+ << chEqual << chDoubleQuote
+ << XMLFormatter::AttrEscapes
+ << attribute.getNodeValue()
+ << XMLFormatter::NoEscapes
+ << chDoubleQuote;
+ }
+
+ //
+ // Test for the presence of children, which includes both
+ // text content and nested elements.
+ //
+ DOM_Node child = toWrite.getFirstChild();
+ if (child != 0)
+ {
+ // There are children. Close start-tag, and output children.
+ // No escapes are legal here
+ *gFormatter << XMLFormatter::NoEscapes << chCloseAngle;
+
+ while( child != 0)
+ {
+ target << child;
+ child = child.getNextSibling();
+ }
+
+ //
+ // Done with children. Output the end tag.
+ //
+ *gFormatter << XMLFormatter::NoEscapes << gEndElement
+ << nodeName << chCloseAngle;
+ }
+ else
+ {
+ //
+ // There were no children. Output the short form close of
+ // the element start tag, making it an empty-element tag.
+ //
+ *gFormatter << XMLFormatter::NoEscapes << chForwardSlash << chCloseAngle;
+ }
+ break;
+ }
+
+
+ case DOM_Node::ENTITY_REFERENCE_NODE:
+ {
+ DOM_Node child;
+#if 0
+ for (child = toWrite.getFirstChild();
+ child != 0;
+ child = child.getNextSibling())
+ {
+ target << child;
+ }
+#else
+ //
+ // Instead of printing the refernece tree
+ // we'd output the actual text as it appeared in the xml file.
+ // This would be the case when -e option was chosen
+ //
+ *gFormatter << XMLFormatter::NoEscapes << chAmpersand
+ << nodeName << chSemiColon;
+#endif
+ break;
+ }
+
+
+ case DOM_Node::CDATA_SECTION_NODE:
+ {
+ *gFormatter << XMLFormatter::NoEscapes << gStartCDATA
+ << nodeValue << gEndCDATA;
+ break;
+ }
+
+
+ case DOM_Node::COMMENT_NODE:
+ {
+ *gFormatter << XMLFormatter::NoEscapes << gStartComment
+ << nodeValue << gEndComment;
+ break;
+ }
+
+
+ case DOM_Node::DOCUMENT_TYPE_NODE:
+ {
+ DOM_DocumentType doctype = (DOM_DocumentType &)toWrite;;
+
+ *gFormatter << XMLFormatter::NoEscapes << gStartDoctype
+ << nodeName;
+
+ DOMString id = doctype.getPublicId();
+ if (id != 0)
+ {
+ *gFormatter << XMLFormatter::NoEscapes << chSpace << gPublic
+ << id << chDoubleQuote;
+ id = doctype.getSystemId();
+ if (id != 0)
+ {
+ *gFormatter << XMLFormatter::NoEscapes << chSpace
+ << chDoubleQuote << id << chDoubleQuote;
+ }
+ }
+ else
+ {
+ id = doctype.getSystemId();
+ if (id != 0)
+ {
+ *gFormatter << XMLFormatter::NoEscapes << chSpace << gSystem
+ << id << chDoubleQuote;
+ }
+ }
+
+ id = doctype.getInternalSubset();
+ if (id !=0)
+ *gFormatter << XMLFormatter::NoEscapes << chOpenSquare
+ << id << chCloseSquare;
+
+ *gFormatter << XMLFormatter::NoEscapes << chCloseAngle;
+ break;
+ }
+
+
+ case DOM_Node::ENTITY_NODE:
+ {
+ *gFormatter << XMLFormatter::NoEscapes << gStartEntity
+ << nodeName;
+
+ DOMString id = ((DOM_Entity &)toWrite).getPublicId();
+ if (id != 0)
+ *gFormatter << XMLFormatter::NoEscapes << gPublic
+ << id << chDoubleQuote;
+
+ id = ((DOM_Entity &)toWrite).getSystemId();
+ if (id != 0)
+ *gFormatter << XMLFormatter::NoEscapes << gSystem
+ << id << chDoubleQuote;
+
+ id = ((DOM_Entity &)toWrite).getNotationName();
+ if (id != 0)
+ *gFormatter << XMLFormatter::NoEscapes << gNotation
+ << id << chDoubleQuote;
+
+ *gFormatter << XMLFormatter::NoEscapes << chCloseAngle << chLF;
+
+ break;
+ }
+
+
+ case DOM_Node::XML_DECL_NODE:
+ {
+ DOMString str;
+
+ *gFormatter << gXMLDecl1 << ((DOM_XMLDecl &)toWrite).getVersion();
+
+ *gFormatter << gXMLDecl2 << gEncodingName;
+
+ str = ((DOM_XMLDecl &)toWrite).getStandalone();
+ if (str != 0)
+ *gFormatter << gXMLDecl3 << str;
+
+ *gFormatter << gXMLDecl4;
+
+ break;
+ }
+
+
+ default:
+ cerr << "Unrecognized node type = "
+ << (long)toWrite.getNodeType() << endl;
+ }
+ return target;
+}
+
+
+
diff --git a/cpp/src/Freeze/Print.h b/cpp/src/Freeze/Print.h
new file mode 100644
index 00000000000..b8ab2926c65
--- /dev/null
+++ b/cpp/src/Freeze/Print.h
@@ -0,0 +1,14 @@
+#ifndef PRINT_H
+#define PRINT_H
+
+#include <ostream>
+
+#include <dom/DOM.hpp>
+
+::std::ostream& operator<<(::std::ostream&, DOM_Node&);
+::std::ostream& operator<< (::std::ostream&, const DOMString&);
+
+void printinit();
+
+
+#endif
diff --git a/cpp/src/Freeze/Test.cpp b/cpp/src/Freeze/Test.cpp
new file mode 100644
index 00000000000..a853347318b
--- /dev/null
+++ b/cpp/src/Freeze/Test.cpp
@@ -0,0 +1,129 @@
+#include <util/PlatformUtils.hpp>
+#include <util/XMLString.hpp>
+#include <util/XMLUniDefs.hpp>
+#include <framework/XMLFormatter.hpp>
+#include <util/TranscodingException.hpp>
+
+#include <dom/DOMString.hpp>
+
+#include <dom/DOM.hpp>
+#include <parsers/DOMParser.hpp>
+#include <sax/SAXParseException.hpp>
+
+#include <Freeze/Transform.h>
+#include <Freeze/Print.h>
+
+#include <iostream>
+#include <string>
+
+#include <Freeze/ErrorHandler.h>
+
+using namespace std;
+
+int
+main(int argc, char** argv)
+{
+ if (argc < 3)
+ {
+ cerr << "Usage: " << argv[0] << " from to" << endl;
+ return EXIT_FAILURE;
+ }
+
+ string from(argv[1]);
+ string to(argv[2]);
+
+ string fromschema = from + ".xsd";
+ DOM_Document fromdoc;
+ string frominstance = from + ".xml";
+ DOM_Document fromschemadoc;
+
+ string toschema = to + ".xsd";
+ DOM_Document toschemadoc;
+ string toinstance = to + ".xml";
+
+ //DOM_Document iceschemadoc;
+
+ //
+ // Read each document.
+ //
+
+ try
+ {
+ XMLPlatformUtils::Initialize();
+ }
+ catch (const XMLException& toCatch)
+ {
+ cout << "Error during initialization! :\n"
+ << DOMString(toCatch.getMessage()) << "\n";
+ return EXIT_FAILURE;
+ }
+ printinit(); // TODO: garbage
+
+ DOMParser parser;
+ parser.setValidationScheme(DOMParser::Val_Auto); // optional.
+ parser.setDoNamespaces(true); // optional
+
+ DOMTreeErrorReporter *errReporter = new DOMTreeErrorReporter();
+ parser.setErrorHandler(errReporter);
+
+ try
+ {
+ parser.parse(fromschema.c_str());
+ fromschemadoc = parser.getDocument();
+
+ parser.parse(frominstance.c_str());
+ fromdoc = parser.getDocument();
+
+ parser.parse(toschema.c_str());
+ toschemadoc = parser.getDocument();
+ }
+ catch (const XMLException& toCatch)
+ {
+ cout << "Exception message is: \n"
+ << DOMString(toCatch.getMessage()) << "\n" ;
+ return EXIT_FAILURE;
+ }
+ catch (const SAXParseException& toCatch)
+ {
+ cout << "Exception message is: \n"
+ << DOMString(toCatch.getMessage()) << "\n" ;
+ return EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ cout << "Unexpected Exception \n" ;
+ return EXIT_FAILURE;
+ }
+
+
+ try
+ {
+ Transformer transformer(fromschemadoc, toschemadoc);
+
+ transformer.transform(cout, fromdoc);
+ cout << endl;
+ }
+ catch(const DOM_DOMException& ex)
+ {
+ cerr << "DOM_DOMException: " << ex.code << endl;
+ }
+ catch(const IllegalTransform& ex)
+ {
+ cerr << ex << endl;
+ }
+ catch(const IncompatibleSchema& ex)
+ {
+ cerr << ex << endl;
+ }
+ catch(const InvalidSchema& ex)
+ {
+ cerr << ex << endl;
+ }
+ catch(const SchemaViolation& ex)
+ {
+ cerr << ex << endl;
+ }
+
+
+ return 0;
+}
diff --git a/cpp/src/Freeze/Transform.cpp b/cpp/src/Freeze/Transform.cpp
new file mode 100644
index 00000000000..b86db6a0f2e
--- /dev/null
+++ b/cpp/src/Freeze/Transform.cpp
@@ -0,0 +1,2047 @@
+// **********************************************************************
+//
+// 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);
+ }
+}
+
diff --git a/cpp/src/Freeze/Transform.h b/cpp/src/Freeze/Transform.h
new file mode 100644
index 00000000000..50ea555715f
--- /dev/null
+++ b/cpp/src/Freeze/Transform.h
@@ -0,0 +1,132 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+#ifndef TRANSFORM_H
+#define TRANSFORM_H
+
+#include <string>
+#include <iosfwd>
+#include <map>
+#include <vector>
+
+#include <dom/DOM.hpp>
+
+class IllegalTransform
+{
+public:
+
+ IllegalTransform(const char* file, int line) : _file(file), _line(line) { }
+ ~IllegalTransform() { }
+
+ const char* file() const { return _file; }
+ int line() const { return _line; }
+
+private:
+
+ const char* _file;
+ int _line;
+};
+
+::std::ostream& operator<<(::std::ostream&, const IllegalTransform&);
+
+class IncompatibleSchema
+{
+public:
+
+ IncompatibleSchema(const char* file, int line) : _file(file), _line(line) { }
+ ~IncompatibleSchema() { }
+
+ const char* file() const { return _file; }
+ int line() const { return _line; }
+
+private:
+
+ const char* _file;
+ int _line;
+};
+
+::std::ostream& operator<<(::std::ostream&, const IncompatibleSchema&);
+
+class InvalidSchema
+{
+public:
+
+ InvalidSchema(const char* file, int line) : _file(file), _line(line) { }
+ ~InvalidSchema() { }
+
+ const char* file() const { return _file; }
+ int line() const { return _line; }
+
+private:
+
+ const char* _file;
+ int _line;
+};
+
+::std::ostream& operator<<(::std::ostream&, const InvalidSchema&);
+
+class SchemaViolation
+{
+public:
+
+ SchemaViolation(const char* file, int line) : _file(file), _line(line) { }
+ ~SchemaViolation() { }
+
+ const char* file() const { return _file; }
+ int line() const { return _line; }
+
+private:
+
+ const char* _file;
+ int _line;
+};
+
+::std::ostream& operator<<(::std::ostream&, const SchemaViolation&);
+
+struct DocumentInfo;
+
+class Transform
+{
+public:
+
+ Transform() { }
+ virtual ~Transform() { }
+
+ virtual void transform(::std::ostream&, const DocumentInfo*, const ::std::string&, DOM_Node) = 0;
+ virtual ::std::ostream& print(::std::ostream&) = 0;
+};
+
+typedef ::std::map< ::std::string, Transform*> TransformMap;
+
+class Transformer
+{
+public:
+
+ Transformer(DOM_Document&, DOM_Document&);
+ ~Transformer();
+
+ void transform(::std::ostream&, DOM_Document&);
+
+private:
+
+ //
+ // Map of local@uri element names to transforms. Needed for actual
+ // transform.
+ //
+ TransformMap _elements;
+
+ //
+ // Map of local@uri class transforms (based on static type). This
+ // information cached for creation of the transform.
+ //
+ TransformMap _staticClassTransforms;
+};
+
+#endif
diff --git a/cpp/src/Slice/XsdVisitor.cpp b/cpp/src/Slice/XsdVisitor.cpp
new file mode 100644
index 00000000000..435989abd99
--- /dev/null
+++ b/cpp/src/Slice/XsdVisitor.cpp
@@ -0,0 +1,518 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+#include <Slice/XsdVisitor.h>
+#include <IceUtil/Functional.h>
+#include <Slice/CPlusPlusUtil.h> // TODO: ???
+
+using namespace std;
+using namespace Slice;
+using namespace IceUtil;
+
+static const string internalId = "_internal.";
+
+Slice::XsdVisitor::XsdVisitor() :
+ _emitElements(true)
+{
+}
+
+Slice::XsdVisitor::XsdVisitor(::std::ostream& os) :
+ O(os),
+ _emitElements(true)
+{
+}
+
+void
+Slice::XsdVisitor::emitElements(bool emitElements)
+{
+ _emitElements = emitElements;
+}
+
+bool
+Slice::XsdVisitor::visitClassDefStart(const ClassDefPtr& p)
+{
+ O << sp;
+
+ string scopeId = containedToId(p);
+
+ //
+ // Emit class-name-type
+ //
+ ostringstream os;
+ os << "xs:complexType name=\"" << internalId << scopeId << p->name() << "Type\" id=\"" << p->scoped() << "\"";
+ O << se(os.str());
+
+ annotate("class");
+
+ O << se("xs:complexContent");
+
+ string extension = "xs:extension base=\"";
+ ClassList bases = p->bases();
+ if (bases.empty() || bases.front()->isInterface())
+ {
+ extension += "ice:_internal.object";
+ }
+ else
+ {
+ extension += "tns:";
+ ClassDefPtr base = bases.front();
+ extension += internalId + containedToId(base) + base->name();
+ }
+ extension += "Type\"";
+
+ O << se(extension);
+
+ DataMemberList dataMembers = p->dataMembers();
+ O << se("xs:sequence");
+ for (DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ emitElement(*q);
+ }
+ O << ee; // xs:sequence
+
+ O << ee; // xs:extension
+ O << ee; // xs:complexContent
+ O << ee; // xs:complexType
+
+ if (_emitElements)
+ {
+ O << sp << nl << "<xs:element name=\"" << scopeId << p->name()
+ << "\" type=\"tns:" << internalId << scopeId << p->name() << "Type\" nillable=\"true\"/>";
+ }
+
+ return true;
+}
+
+bool
+Slice::XsdVisitor::visitExceptionStart(const ExceptionPtr& p)
+{
+ O << sp;
+
+ string scopeId = containedToId(p);
+
+ //
+ // Emit exception-name-type
+ //
+ ostringstream os;
+ os << "xs:complexType name=\"" << internalId << scopeId << p->name() << "Type\" id=\"" << p->scoped() << "\"";
+ O << se(os.str());
+
+ annotate("exception");
+
+ //
+ // Emit base Data
+ //
+ ExceptionPtr base = p->base();
+ if (base)
+ {
+ string baseScopeId = containedToId(base);
+
+ O << se("xs:complexContent");
+
+ string extension = "xs:extension base=\"";
+ extension += "tns:";
+ extension += internalId + baseScopeId + base->name();
+ extension += "Type\"";
+ O << se(extension);
+ }
+
+ DataMemberList dataMembers = p->dataMembers();
+
+ O << se("xs:sequence");
+
+ for (DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ emitElement(*q);
+ }
+
+ O << ee; // xs:sequence
+
+ if (base)
+ {
+ O << ee; // xs:extension
+ O << ee; // xs:complexContent
+ }
+
+ O << ee; // xs:complexType
+
+ if (_emitElements)
+ {
+ O << sp << nl << "<xs:element name=\"" << scopeId << p->name()
+ << "\" type=\"tns:" << internalId << scopeId << p->name() << "Type\"/>";
+ }
+
+ return true;
+}
+
+bool
+Slice::XsdVisitor::visitStructStart(const StructPtr& p)
+{
+ O << sp;
+
+ string scopeId = containedToId(p);
+
+ ostringstream os;
+ os << "xs:complexType name=\"" << internalId << scopeId << p->name() << "Type\" id=\"" << p->scoped() << "\"";
+ O << se(os.str());
+
+ annotate("struct");
+
+ DataMemberList dataMembers = p->dataMembers();
+ O << se("xs:sequence");
+
+ for (DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ O << nl << "<xs:element name=\"" << (*q)->name() << "\" type=\"";
+ O << toString((*q)->type());
+ O << "\"/>";
+ }
+
+ O << ee; // xs:sequence
+
+ O << ee; // xs:complexType
+
+ if (_emitElements)
+ {
+ O << sp << nl << "<xs:element name=\"" << scopeId << p->name()
+ << "\" type=\"tns:" << internalId << scopeId << p->name() << "Type\"/>";
+ }
+
+ return true;
+}
+
+void
+Slice::XsdVisitor::visitOperation(const OperationPtr& p)
+{
+ TypeStringList in = p->inputParameters();
+ TypeStringList out = p->outputParameters();
+ TypePtr ret = p->returnType();
+ string scopeId = containedToId(p);
+ ostringstream os;
+
+ O << sp;
+
+ os << "xs:element name=\"" << scopeId << "request." << p->name() << "\"";
+ O << se(os.str());
+ O << se("xs:complexType");
+
+ annotate("operation");
+
+ O << se("xs:sequence");
+ TypeStringList::const_iterator q;
+ for (q = in.begin(); q != in.end(); ++q)
+ {
+ emitElement(*q);
+ }
+ O << ee; // xs:sequence
+
+ O << ee; // xs:complexType
+ O << ee; // xs:element
+
+ os.str(""); // Reset stream
+
+ O << sp;
+
+ os << "xs:element name=\"" << scopeId << "reply." << p->name() << "\"";
+ O << se(os.str());
+ O << se("xs:complexType");
+
+ annotate("operation");
+
+ O << se("xs:sequence");
+ if (ret)
+ {
+ O << nl << "<xs:element name=\"__return\" type=\"" << toString(ret) << "\"/>";
+ }
+ for (q = out.begin(); q != out.end(); ++q)
+ {
+ emitElement(*q);
+ }
+ O << ee; // xs:sequence
+
+ O << ee; // xs:complexType
+ O << ee; // xs:element
+}
+
+void
+Slice::XsdVisitor::visitEnum(const EnumPtr& p)
+{
+ string scopeId = containedToId(p);
+
+ O << sp;
+
+ ostringstream os;
+ os << "xs:simpleType name=\"" << internalId << scopeId << p->name() << "Type\" id=\"" << p->scoped() << "\"";
+ O << se(os.str());
+
+ annotate("enumeration");
+
+ EnumeratorList enumerators = p->getEnumerators();
+ assert (!enumerators.empty());
+
+ O << se("xs:restriction base=\"xs:string\"");
+
+ for (EnumeratorList::const_iterator q = enumerators.begin(); q != enumerators.end(); ++q)
+ {
+ O << nl << "<xs:enumeration value=\"" << (*q)->name() << "\"/>";
+ }
+
+ O << ee; // xs:restriction
+ O << ee; // xs:simpleType
+
+ if (_emitElements)
+ {
+ O << sp << nl << "<xs:element name=\"" << scopeId << p->name()
+ << "\" type=\"tns:" << internalId << scopeId << p->name() << "Type\"/>";
+ }
+}
+
+void
+Slice::XsdVisitor::visitSequence(const SequencePtr& p)
+{
+ O << sp;
+
+ string scopeId = containedToId(p);
+
+ ostringstream os;
+ os << "xs:complexType name=\"" << internalId << scopeId << p->name() << "Type\" id=\"" << p->scoped() << "\"";
+
+ O << se(os.str());
+
+ annotate("sequence");
+
+ O << se("xs:sequence");
+
+ O << nl << "<xs:element name=\"e\" type=\"" << toString(p->type())
+ << "\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>";
+
+ O << ee; // xs:sequence
+
+ O << nl << "<xs:attribute name=\"length\" type=\"xs:long\"/>";
+
+ O << ee; // xs:complexType
+
+ if (_emitElements)
+ {
+ O << sp << nl << "<xs:element name=\"" << scopeId << p->name() << "\" type=\"tns:"
+ << internalId << scopeId << p->name() << "Type\"/>";
+ }
+}
+
+void
+Slice::XsdVisitor::visitDictionary(const DictionaryPtr& p)
+{
+ O << sp;
+
+ string scopeId = containedToId(p);
+
+ //
+ // First the dictionary content.
+ //
+ ostringstream os;
+ os << "xs:complexType name=\"" << internalId << scopeId << p->name() << "ContentType\"";
+ O << se(os.str());
+
+ annotate("dictionaryContent");
+
+ O << se("xs:sequence");
+
+ O.inc();
+ O << nl << "<xs:element name=\"key\" type=\"" << toString(p->keyType()) << "\"/>";
+ O << nl << "<xs:element name=\"value\" type=\"" << toString(p->valueType()) << "\"/>";
+ O.dec();
+
+ O << ee; // xs:sequence
+ O << ee; // xs:complexType
+
+ O << sp;
+
+ //
+ // Next the dictionary sequence data.
+ //
+ os.str("");
+ os << "xs:complexType name=\"" << internalId << scopeId << p->name() << "Type\" id=\"" << p->scoped() << "\"";
+ O << se(os.str());
+
+ annotate("dictionary");
+
+ O << se("xs:sequence");
+
+ O << nl << "<xs:element name=\"e\" type=\"tns:" << internalId << scopeId << p->name() << "ContentType\""
+ << " minOccurs=\"0\" maxOccurs=\"unbounded\"/>";
+
+ O << ee; // xs:sequence
+
+ O << nl << "<xs:attribute name=\"length\" type=\"xs:long\"/>";
+
+ O << ee; // xs:complexType
+
+ if (_emitElements)
+ {
+ O << sp << nl << "<xs:element name=\"" << scopeId << p->name() << "\" type=\"tns:"
+ << internalId << scopeId << p->name() << "Type\"/>";
+ }
+}
+
+void
+Slice::XsdVisitor::annotate(const ::std::string& type)
+{
+ O << se("xs:annotation");
+ O << se("xs:appinfo");
+ O << nl << "<type>" << type << "</type>";
+ O << ee; // xs:annotation
+ O << ee; // xs:appinfo
+}
+
+void
+Slice::XsdVisitor::emitElement(const DataMemberPtr& q)
+{
+ ostringstream os;
+ os << "xs:element name=\"" << q->name() << "\" type=\"" << toString(q->type()) << '"';
+ O << se(os.str());
+ ProxyPtr proxy = ProxyPtr::dynamicCast(q->type());
+ if (proxy)
+ {
+ annotate(proxy->_class()->scoped());
+ }
+ O << ee; // xs:element
+}
+
+void
+Slice::XsdVisitor::emitElement(const TypeString& q)
+{
+ ostringstream os;
+ os << "xs:element name=\"" << q.second << "\" type=\"" << toString(q.first) << '"';
+ O << se(os.str());
+ ProxyPtr proxy = ProxyPtr::dynamicCast(q.first);
+ if (proxy)
+ {
+ annotate(proxy->_class()->scoped());
+ }
+ O << ee; // xs:element
+}
+
+string
+Slice::XsdVisitor::containedToId(const ContainedPtr& contained)
+{
+ assert(contained);
+
+ string scoped = contained->scope();
+ if (scoped[0] == ':')
+ {
+ scoped.erase(0, 2);
+ }
+
+ string id;
+
+ id.reserve(scoped.size());
+
+ for (unsigned int i = 0; i < scoped.size(); ++i)
+ {
+ if (scoped[i] == ':')
+ {
+ id += '.';
+ ++i;
+ }
+ else
+ {
+ id += scoped[i];
+ }
+ }
+
+ return id;
+}
+
+string
+Slice::XsdVisitor::toString(const SyntaxTreeBasePtr& p)
+{
+ string tag;
+ string linkend;
+ string s;
+
+ static const char* builtinTable[] =
+ {
+ "xs:byte",
+ "xs:boolean",
+ "xs;short",
+ "xs:int",
+ "xs:long",
+ "xs:float",
+ "xs:double",
+ "xs:string",
+ "ice:_internal.reference", /* Object */
+ "ice:_internal.proxyType", /* Object* */
+ "???" /* LocalObject */
+ };
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(p);
+ if (builtin)
+ {
+ s = builtinTable[builtin->kind()];
+ //tag = "type";
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(p);
+ if (proxy)
+ {
+ s = "ice:_internal.proxyType";
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(p);
+ if (cl)
+ {
+ string scopeId = containedToId(cl);
+ //s = "tns:" + internalId + scopeId + cl->name() + "Type";
+ s = "ice:_internal.reference";
+ }
+
+ ExceptionPtr ex = ExceptionPtr::dynamicCast(p);
+ if (ex)
+ {
+ string scopeId = containedToId(ex);
+ s = "tns:" + internalId + scopeId + ex->name() + "Type";
+ }
+
+ StructPtr st = StructPtr::dynamicCast(p);
+ if (st)
+ {
+ string scopeId = containedToId(st);
+ s = "tns:" + internalId + scopeId + st->name() + "Type";
+ }
+
+ EnumeratorPtr en = EnumeratorPtr::dynamicCast(p);
+ if (en)
+ {
+ string scopeId = containedToId(en);
+ s = "tns:" + internalId + scopeId + en->name() + "Type";
+ }
+
+ SequencePtr sq = SequencePtr::dynamicCast(p);
+ if (sq)
+ {
+ string scopeId = containedToId(sq);
+ s = "tns:" + internalId + scopeId + sq->name() + "Type";
+ }
+
+ DictionaryPtr di = DictionaryPtr::dynamicCast(p);
+ if (di)
+ {
+ string scopeId = containedToId(di);
+ s = "tns:" + internalId + scopeId + di->name() + "Type";
+ }
+
+ EnumPtr em = EnumPtr::dynamicCast(p);
+ if (em)
+ {
+ string scopeId = containedToId(em);
+ s = "tns:" + internalId + scopeId + em->name() + "Type";
+ }
+
+ return s;
+}