summaryrefslogtreecommitdiffstats
path: root/sdo-cpp/branches/sdo-cpp-pre2.1/runtime/core/src/commonj/sdo/SDOXMLWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sdo-cpp/branches/sdo-cpp-pre2.1/runtime/core/src/commonj/sdo/SDOXMLWriter.cpp')
-rw-r--r--sdo-cpp/branches/sdo-cpp-pre2.1/runtime/core/src/commonj/sdo/SDOXMLWriter.cpp1410
1 files changed, 1410 insertions, 0 deletions
diff --git a/sdo-cpp/branches/sdo-cpp-pre2.1/runtime/core/src/commonj/sdo/SDOXMLWriter.cpp b/sdo-cpp/branches/sdo-cpp-pre2.1/runtime/core/src/commonj/sdo/SDOXMLWriter.cpp
new file mode 100644
index 0000000000..728023a59a
--- /dev/null
+++ b/sdo-cpp/branches/sdo-cpp-pre2.1/runtime/core/src/commonj/sdo/SDOXMLWriter.cpp
@@ -0,0 +1,1410 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#include "commonj/sdo/SDOXMLWriter.h"
+#include "commonj/sdo/SDOXMLString.h"
+#include "commonj/sdo/SDOString.h"
+#include "iostream"
+using namespace::std;
+#include "commonj/sdo/DASProperty.h"
+#include "commonj/sdo/XSDPropertyInfo.h"
+#include "commonj/sdo/XSDTypeInfo.h"
+#include "commonj/sdo/ChangeSummary.h"
+#include "commonj/sdo/Sequence.h"
+#include "commonj/sdo/SDORuntimeException.h"
+#include "commonj/sdo/XMLQName.h"
+#include "commonj/sdo/DataObjectImpl.h"
+#include "commonj/sdo/DataFactoryImpl.h"
+#include "commonj/sdo/PropertySetting.h"
+#include "commonj/sdo/SDOUtils.h"
+
+namespace commonj
+{
+ namespace sdo
+ {
+
+ const SDOXMLString SDOXMLWriter::s_xsi("xsi");
+ const SDOXMLString SDOXMLWriter::s_type("type");
+ const SDOXMLString SDOXMLWriter::s_nil("nil");
+ const SDOXMLString SDOXMLWriter::s_true("true");
+ const SDOXMLString SDOXMLWriter::s_xsiNS("http://www.w3.org/2001/XMLSchema-instance");
+ const SDOXMLString SDOXMLWriter::s_xmlns("xmlns");
+ const SDOXMLString SDOXMLWriter::s_commonjsdo("commonj.sdo");
+ const SDOXMLString SDOXMLWriter::s_wsdluri("http://schemas.xmlsoap.org/wsdl/");
+ const SDOXMLString SDOXMLWriter::s_wsdl("wsdl");
+ const SDOXMLString SDOXMLWriter::s_soapuri("http://schemas.xmlsoap.org/wsdl/soap/");
+ const SDOXMLString SDOXMLWriter::s_soap("soap");
+ const SDOXMLString SDOXMLWriter::s_httpuri("http://schemas.xmlsoap.org/wsdl/http/");
+ const SDOXMLString SDOXMLWriter::s_http("http");
+
+
+ SDOXMLWriter::SDOXMLWriter(
+ DataFactoryPtr dataFact)
+ : dataFactory(dataFact)
+ {
+
+ }
+
+ SDOXMLWriter::~SDOXMLWriter()
+ {
+ freeWriter();
+ }
+
+ void SDOXMLWriter::setWriter(xmlTextWriterPtr textWriter)
+ {
+ writer = textWriter;
+ }
+
+ void SDOXMLWriter::freeWriter()
+ {
+ if (writer != NULL)
+ {
+ xmlFreeTextWriter(writer);
+ writer = NULL;
+ }
+ }
+
+ int SDOXMLWriter::write(XMLDocumentPtr doc, int indent)
+ {
+ if (!doc)
+ {
+ return 0;
+ }
+
+ if (writer == NULL)
+ {
+ // Throw exception
+ return -1;
+ }
+
+ int rc = 0;
+ namespaceMap.empty();
+
+ if (indent >= 0)
+ {
+ xmlTextWriterSetIndent(writer, 1);
+ if (indent > 0)
+ {
+ char * chars = new char[indent+1];
+ for (int i=0;i<indent;i++)chars[i] = ' ';
+ chars[indent] = 0;
+ xmlTextWriterSetIndentString(writer, SDOXMLString(chars));
+ delete[] chars;
+ }
+ else
+ {
+ xmlTextWriterSetIndentString(writer, SDOXMLString(""));
+ }
+ }
+
+ if (doc->getXMLDeclaration())
+ {
+ rc = xmlTextWriterStartDocument(writer, doc->getXMLVersion(), doc->getEncoding(), NULL);
+ if (rc < 0) {
+ SDO_THROW_EXCEPTION("write", SDOXMLParserException, "xmlTextWriterStartDocument failed");
+ }
+ }
+
+ DataObjectPtr root = doc->getRootDataObject();
+ if (root)
+ {
+ const Type& rootType = root->getType();
+ SDOXMLString rootTypeURI = rootType.getURI();
+ SDOXMLString rootTypeName = rootType.getName();
+
+ // For the root DataObject we need to determine the element name
+ SDOXMLString elementURI = doc->getRootElementURI();
+ SDOXMLString elementName = doc->getRootElementName();
+ if (elementName.isNull() || elementName.equals(""))
+ {
+ elementName = rootTypeName;
+ elementName = elementName.toLower(0,1);
+ }
+
+ // If the element name is defined as a global element then we
+ // can supress the writing of xsi:type according to the spec
+ bool writeXSIType = true;
+
+ try
+ {
+ // Locate the RootType
+ const Type& rootTy = dataFactory->getType(elementURI, "RootType");
+ // Does a property exist with the given element name?
+ const Property& rootProp = rootTy.getProperty((const char*)elementName);
+ // Is this property of the correct Type?
+ const Type& rootPropType = rootProp.getType();
+ if (rootTypeURI == (SDOXMLString)rootPropType.getURI()
+ && rootTypeName == (SDOXMLString)rootPropType.getName())
+ {
+ writeXSIType = false;
+ }
+ }
+ catch(SDORuntimeException&)
+ {
+ }
+
+ // Supress the writing of xsi:type as well for DataObjects of type
+ // commonj.sdo#OpenDataObject
+ if (writeXSIType &&
+ rootTypeURI.equals("commonj.sdo") && rootTypeName.equals("OpenDataObject"))
+ {
+ writeXSIType = false;
+ }
+
+ writeDO(root, elementURI, elementName, writeXSIType, true);
+ }
+ rc = xmlTextWriterEndDocument(writer);
+ if (rc < 0) {
+ SDO_THROW_EXCEPTION("write", SDOXMLParserException, "xmlTextWriterEndDocument failed");
+ return rc;
+ }
+
+ xmlTextWriterFlush(writer);
+ freeWriter();
+
+ return rc;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Write Change Summary attributes
+ //////////////////////////////////////////////////////////////////////////
+
+ void SDOXMLWriter::handleChangeSummaryAttributes(
+ ChangeSummaryPtr cs,
+ DataObjectPtr dol)
+ {
+ int rc;
+
+ SettingList& sl = cs->getOldValues(dol);
+ if (sl.size() == 0)
+ {
+ // no attributes
+ return;
+ }
+ for (int j=0;j< sl.size(); j++)
+ {
+ try {
+
+ if (sl.get(j)->getProperty().isMany())
+ {
+ // manys are elements
+ continue;
+ }
+
+ if (sl.get(j)->getProperty().getType().isDataType())
+ {
+ // data types are OK
+ rc = xmlTextWriterWriteAttribute(writer,
+ SDOXMLString(sl.get(j)->getProperty().getName()),
+ SDOXMLString(sl.get(j)->getCStringValue()));
+ }
+ else
+ {
+ DataObjectPtr dob = sl.get(j)->getDataObjectValue();
+ if (dob)
+ {
+ if (cs->isDeleted(dob))
+ {
+ rc = xmlTextWriterWriteAttribute(writer,
+ SDOXMLString(sl.get(j)->getProperty().getName()),
+ SDOXMLString(cs->getOldXpath(dob)));
+ }
+ else
+ {
+ rc = xmlTextWriterWriteAttribute(writer,
+ SDOXMLString(sl.get(j)->getProperty().getName()),
+ SDOXMLString(dob->objectToXPath()));
+ }
+ }
+ else
+ {
+ rc = xmlTextWriterWriteAttribute(writer,
+ SDOXMLString(sl.get(j)->getProperty().getName()),
+ SDOXMLString(""));
+ }
+ }
+ }
+ catch (SDORuntimeException e)
+ {
+ // ignore this attribute
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Write Change Summary elements
+ //////////////////////////////////////////////////////////////////////////
+
+ void SDOXMLWriter::handleChangeSummaryElements(
+ ChangeSummaryPtr cs,
+ DataObjectPtr dob)
+ {
+ int rc;
+
+ SettingList& sl = cs->getOldValues(dob);
+
+ if (sl.size() == 0)
+ {
+ // there are no setting for this element.
+ return;
+ }
+
+ for (int j=0;j< sl.size(); j++)
+ {
+ try
+ {
+
+ // single values will have been covered by the attributes.
+ if (!sl.get(j)->getProperty().isMany()) continue;
+
+ if (sl.get(j)->getProperty().getType().isDataType())
+ {
+
+ rc = xmlTextWriterWriteElement(
+ writer,
+ SDOXMLString(sl.get(j)->getProperty().getName()),
+ SDOXMLString(sl.get(j)->getCStringValue()));
+
+ } // if datatype
+ else
+ {
+ DataObjectPtr dob2 = sl.get(j)->getDataObjectValue();
+ if (!dob2)
+ {
+ continue;
+ }
+ if (cs->isDeleted(dob2))
+ {
+ handleChangeSummaryDeletedObject(sl.get(j)->getProperty().getName(), cs,dob2);
+ }
+ else
+ {
+ rc = xmlTextWriterStartElement(
+ writer,
+ SDOXMLString(sl.get(j)->getProperty().getName()));
+ rc = xmlTextWriterWriteAttribute(
+ writer,
+ SDOXMLString("sdo:ref"),
+ SDOXMLString(dob2->objectToXPath()));
+ rc = xmlTextWriterEndElement(
+ writer);
+ }
+ }
+ }
+ catch (SDORuntimeException e)
+ {
+ // ignore this element
+ }
+ } // for
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Write a deleted object and all its props
+ //////////////////////////////////////////////////////////////////////////
+
+ void SDOXMLWriter::handleChangeSummaryDeletedObject(
+ const char* name,
+ ChangeSummaryPtr cs,
+ DataObjectPtr dob)
+ {
+
+ int rc, k; // TODO error handling
+
+ SettingList& sl = cs->getOldValues(dob);
+
+ rc = xmlTextWriterStartElement(
+ writer,
+ SDOXMLString(name));
+
+ if (sl.size() == 0)
+ {
+ rc = xmlTextWriterWriteAttribute(writer,
+ SDOXMLString("sdo:ref"),
+ SDOXMLString(cs->getOldXpath(dob)));
+ rc = xmlTextWriterEndElement(writer);
+ return;
+ }
+
+
+ try
+ {
+ // print single valued datatypes as attributes
+
+ for (int j=0;j< sl.size(); j++)
+ {
+ //if (!sl.get(j)->isSet())
+ //{
+ // // unset properties dont need recording - ah but they do!
+ //
+ // continue;
+ //}
+ if ( sl.get(j)->getProperty().isMany())
+ {
+ // manys are elements
+ continue;
+ }
+ if (!sl.get(j)->getProperty().getType().isDataType())
+ {
+ // data objects are element in a deleted data object.
+ continue;
+ }
+
+ rc = xmlTextWriterWriteAttribute(writer,
+ SDOXMLString(sl.get(j)->getProperty().getName()),
+ SDOXMLString(sl.get(j)->getCStringValue()));
+
+ } // for attributes
+
+
+ // now we are onto the many-values,
+ // and dataobject single values.
+ //
+ // handle deletions within deletions in reverse order, so they match the
+ // deletion records above.
+
+ for (k=sl.size()-1;k>=0; k--)
+ {
+
+ if ( !sl.get(k)->getProperty().getType().isDataType() &&
+ sl.get(k)->getProperty().isMany())
+ {
+ // its a dataobject type
+ DataObjectPtr dob2 = sl.get(k)->getDataObjectValue();
+ if (!dob2) continue;
+ if (!cs->isDeleted(dob2)) continue;
+ handleChangeSummaryDeletedObject(sl.get(k)->
+ getProperty().getName(),cs,dob2);
+ }
+ } // for attributes
+
+ for (k=0;k< sl.size(); k++)
+ {
+
+ if ( !sl.get(k)->getProperty().getType().isDataType())
+ {
+ if (sl.get(k)->getProperty().isMany()) continue;
+ // its a single valued dataobject type
+
+ DataObjectPtr dob2 = sl.get(k)->getDataObjectValue();
+ if (!dob2) continue;
+ if (!cs->isDeleted(dob2)) continue;
+ handleChangeSummaryDeletedObject(sl.get(k)->
+ getProperty().getName(),cs,dob2);
+
+ }
+ else
+ {
+ if ( !sl.get(k)->getProperty().isMany()) continue;
+
+ // could only be many valued data type
+
+ rc = xmlTextWriterWriteElement(writer,
+ SDOXMLString(sl.get(k)->getProperty().getName()),
+ SDOXMLString(sl.get(k)->getCStringValue()));
+ }
+ } // for attributes
+ }
+ catch (SDORuntimeException e)
+ {
+ // ignore - and write the end-element
+ }
+
+ rc = xmlTextWriterEndElement(writer);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Write the list of elements of a change summary
+ //////////////////////////////////////////////////////////////////////////
+
+ void SDOXMLWriter::handleSummaryChange(
+ const SDOXMLString& elementName,
+ ChangeSummaryPtr cs,
+ DataObjectPtr dob)
+ {
+ int rc;
+ DataObject* temp = dob;
+ const char* name;
+ try
+ {
+ name = temp->getContainmentProperty().getName();
+ }
+ catch (SDORuntimeException e)
+ {
+ // This could be a root, and have no name.
+ name = 0;
+ }
+
+ if (name == 0)
+ {
+ rc = xmlTextWriterStartElement(
+ writer,
+ elementName);
+ }
+ else
+ {
+ rc = xmlTextWriterStartElement(
+ writer,
+ SDOXMLString(name));
+ }
+
+ if (rc != 0)
+ {
+ // failed to write an element
+ return;
+ }
+
+ try
+ {
+ name = temp->objectToXPath();
+ }
+ catch (SDORuntimeException e)
+ {
+ name = 0;
+ }
+
+ rc = xmlTextWriterWriteAttribute(writer,
+ SDOXMLString("sdo:ref"),
+ SDOXMLString(name));
+
+ handleChangeSummaryAttributes(cs, temp);
+
+ handleChangeSummaryElements(cs, temp);
+
+ rc = xmlTextWriterEndElement(writer);
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Write a Change Summary
+ //////////////////////////////////////////////////////////////////////////
+
+ void SDOXMLWriter::handleChangeSummary(
+ const SDOXMLString& elementName,
+ ChangeSummaryPtr cs)
+ {
+ unsigned int i;
+ int rc;
+
+ ChangedDataObjectList& changedDOs = cs->getChangedDataObjects();
+ rc = xmlTextWriterStartElementNS(writer,
+ SDOXMLString("sdo"), SDOXMLString("changeSummary"), SDOXMLString(Type::SDOTypeNamespaceURI.c_str()));
+ if (rc != 0) return;
+ if (cs->isLogging())
+ {
+ rc = xmlTextWriterWriteAttribute(writer,
+ SDOXMLString("logging"),
+ SDOXMLString("true"));
+ }
+
+ if (changedDOs.size() > 0)
+ {
+
+ // write the creates/deletes in the order they
+ // happened, as elements.
+
+ for (i=0;i< changedDOs.size();i++)
+ {
+ if (cs->isCreated(changedDOs[i])
+ && changedDOs.getType(i) == ChangedDataObjectList::Create)
+ {
+ // TODO - should work out if theres a IDREF here
+ // TODO - can we have more than one create like this?
+ try
+ {
+ rc = xmlTextWriterWriteElement(writer,
+ SDOXMLString("create"),
+ SDOXMLString(changedDOs[i]->objectToXPath()));
+ }
+ catch (SDORuntimeException e)
+ {
+ // The object was not in our tree - we ignore it.
+ }
+ }
+ if (cs->isDeleted(changedDOs[i])
+ && changedDOs.getType(i) == ChangedDataObjectList::Delete)
+ {
+ // TODO - should work out if theres a IDREF here
+ try
+ {
+ rc = xmlTextWriterWriteElement(writer,
+ SDOXMLString("delete"),
+ SDOXMLString(cs->getOldXpath(changedDOs[i])));
+ }
+ catch (SDORuntimeException e)
+ {
+ // The object was not in the deleted list - we ignore it.
+ }
+ }
+ }
+
+
+ for (i=0;i< changedDOs.size();i++)
+ {
+ if (cs->isModified(changedDOs[i]))
+ {
+ handleSummaryChange(elementName, cs, changedDOs[i]);
+ }
+ }
+
+ }
+ rc = xmlTextWriterEndElement(writer);
+ }
+
+ void SDOXMLWriter::addNamespace(const SDOXMLString& uri, bool tns)
+ {
+ std::map<SDOXMLString,SDOXMLString>::iterator it = namespaceMap.find(uri);
+ if (it == namespaceMap.end())
+ {
+ SDOXMLString prefix = "tns";
+ // Handle some common namespaces
+ if (uri.equals(s_wsdluri))
+ {
+ prefix = s_wsdl;
+ }
+ else if (uri.equals(s_soapuri))
+ {
+ prefix = s_soap;
+ }
+ else if (uri.equals(s_httpuri))
+ {
+ prefix = s_http;
+ }
+ else if (!tns)
+ {
+ char buf[20];
+ sprintf(buf,"%d", namespaceMap.size());
+ prefix += buf;
+ }
+ namespaceMap[uri] = prefix;
+ }
+
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Add to namespaces
+ //////////////////////////////////////////////////////////////////////////
+
+ void SDOXMLWriter::addToNamespaces(DataObjectImpl* dob)
+ {
+ std::map<SDOXMLString,SDOXMLString>::iterator it;
+ SDOXMLString uri = dob->getType().getURI();
+ SDOXMLString typeName = dob->getType().getName();
+ if (!(uri.equals("commonj.sdo") && typeName.equals("OpenDataObject")))
+ {
+ addNamespace(uri);
+ }
+
+ PropertyList pl = dob->getInstanceProperties();
+ for (unsigned int i = 0; i < pl.size(); i++)
+ {
+ if (!dob->isSet(pl[i]))continue;
+
+ if (pl[i].isMany())
+ {
+ if (!pl[i].getType().isDataType())
+ {
+ DataObjectList& dl = dob->getList(pl[i]);
+ for (unsigned int k=0;k< dl.size() ;k++)
+ {
+ DataObjectImpl* d = (DataObjectImpl*)(DataObject*)dl[k];
+ if (d != 0)addToNamespaces(d);
+ }
+ }
+ }
+ else
+ {
+ if (!pl[i].getType().isDataType())
+ {
+ DataObjectImpl* d = (DataObjectImpl*)(DataObject*)dob->getDataObject(pl[i]);
+ if (d != 0)addToNamespaces(d);
+ }
+ else
+ {
+ XSDPropertyInfo* pi = getPropertyInfo(pl[i]);
+ if (pi)
+ {
+ PropertyDefinitionImpl propdef;
+ propdef = pi->getPropertyDefinition();
+ if (propdef.isElement)continue;
+ if (!propdef.isQName)continue;
+
+ SDOXMLString propertyValue = (dob->getCString(pl[i]));
+ XMLQName qname(propertyValue);
+
+ SDOXMLString qnameuri = qname.getURI();
+ if (qnameuri.equals("") || qnameuri.isNull() )
+ {
+ continue;
+ }
+
+ it = namespaceMap.find(qnameuri);
+ if (it == namespaceMap.end())
+ {
+ addNamespace(qnameuri);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * WriteDO - write a DataObject tree
+ *
+ */
+
+ int SDOXMLWriter::writeDO(
+ DataObjectPtr dataObject,
+ const SDOXMLString& elementURI,
+ const SDOXMLString& elementName,
+ bool writeXSIType,
+ bool isRoot)
+ {
+
+ int rc;
+
+ if (dataObject == 0)
+ return 0;
+
+ const Type& dataObjectType = dataObject->getType();
+ SDOXMLString typeURI = dataObjectType.getURI();
+ SDOXMLString typeName = dataObjectType.getName();
+ bool isOpen = dataObjectType.isOpenType();
+ DataObjectImpl* dataObjectImpl = (DataObjectImpl*)(DataObject*)dataObject;
+ const TypeImpl& typeImpl = dataObjectImpl->getTypeImpl();
+
+
+ // ---------------------------------------
+ // First we need to write the startElement
+ if (isRoot)
+ {
+ // For the root element we will now gather all the namespace information
+ addNamespace(elementURI, true);
+
+ // We always add the xsi namespace. TODO we should omit if we can
+ namespaceMap[s_xsiNS] = s_xsi;
+
+ DataObjectImpl* d = (DataObjectImpl*)(DataObject*)dataObject;
+ addToNamespaces(d);
+
+ if (elementURI.equals(s_commonjsdo))
+ {
+ tnsURI = "";
+ }
+ else
+ {
+ tnsURI = elementURI;
+ }
+ }
+ // Write the startElement for non-root object
+ SDOXMLString theName=elementName;
+
+ // If an elementURI is specified then the elementForm is "qualified"
+ if (!elementURI.isNull()
+ && !elementURI.equals("")
+ && !elementURI.equals(s_commonjsdo)
+ //&& !elementURI.equals(tnsURI)
+ )
+ {
+ // Locate the namespace prefix
+ std::map<SDOXMLString,SDOXMLString>::iterator it = namespaceMap.find(elementURI);
+ if (it != namespaceMap.end())
+ {
+ theName = (*it).second;
+ theName += ":";
+ theName += elementName;
+ }
+ }
+
+ rc = xmlTextWriterStartElement(writer, theName);
+ if (rc < 0) {
+ SDO_THROW_EXCEPTION("writeDO", SDOXMLParserException, "xmlTextWriterStartElement failed");
+ }
+
+ // End - startElement is written
+ // -----------------------------
+
+
+ // -------------------------------------------
+ // For a primitive type - just write the value
+ if (dataObjectType.isDataType())
+ {
+ if (dataObject->isNull(""))
+ {
+ rc = xmlTextWriterWriteAttributeNS(writer, s_xsi, s_nil, NULL, s_true);
+ }
+ else
+ {
+ /* Use our wrapper function just in case the element has CDATA in it */
+ writeXMLElement(writer,
+ elementName,
+ dataObject->getCString(""));
+ }
+
+ // Write the end element and return
+ rc = xmlTextWriterEndElement(writer);
+ return 0;
+ }
+ // End - primitive value is written
+ // --------------------------------
+
+
+ //-------------------------------------------
+ // Write the xsi:type= attribute if necessary
+ if (writeXSIType)
+ {
+ // Supress the writing of xsi:type as well for DataObjects of type
+ // commonj.sdo#OpenDataObject
+ if (typeURI.equals("commonj.sdo") && typeName.equals("OpenDataObject"))
+ {
+ }
+ else
+ {
+ SDOXMLString theName=typeName;
+
+ if (!typeURI.isNull() && !typeURI.equals(""))
+ {
+ std::map<SDOXMLString,SDOXMLString>::iterator it = namespaceMap.find(typeURI);
+ if (it != namespaceMap.end())
+ {
+ theName = (*it).second;
+ theName += ":";
+ theName += typeName;
+ }
+ }
+
+ rc = xmlTextWriterWriteAttributeNS(writer,
+ s_xsi, s_type,
+ NULL,
+ theName);
+ }
+ }
+ // End - xsi:type= attribute is written
+ // ------------------------------------
+
+
+ // -------------------------------
+ // Write the namespace information
+ if (isRoot)
+ {
+ // Now write all the namespace information
+ for (std::map<SDOXMLString,SDOXMLString>::iterator it = namespaceMap.begin();
+ it != namespaceMap.end(); ++it)
+ {
+ if ((*it).first.equals("")) continue;
+ rc = xmlTextWriterWriteAttributeNS(writer, s_xmlns, (*it).second, NULL, (*it).first);
+ }
+ }
+ // End - namespace information is written
+ // --------------------------------------
+
+
+ // ---------------------
+ // write nil if required
+ if (dataObject->isNull(""))
+ {
+ rc = xmlTextWriterWriteAttributeNS(writer, s_xsi, s_nil, NULL, s_true);
+ }
+ // xsi:nil is written
+ // ------------------
+
+
+ // --------------------------------------------------
+ // Iterate over all the properties to find attributes
+ unsigned int i;
+ unsigned int j = 1;
+ PropertyList pl = dataObject->getInstanceProperties();
+ for (i = 0; i < pl.size(); i++)
+ {
+ if (dataObject->isSet(pl[i]))
+ {
+ SDOXMLString propertyName(pl[i].getName());
+ XSDPropertyInfo* pi = getPropertyInfo(pl[i]);
+ PropertyDefinitionImpl propdef;
+ if (pi)
+ {
+ propdef = pi->getPropertyDefinition();
+ propertyName = propdef.localname;
+ }
+
+ // Elements are written as <element>
+ if (propdef.isElement)
+ continue;
+
+ // Many-valued properties are written as <element>
+ if (pl[i].isMany())
+ continue;
+
+ // Non contained properties become attributes
+ const Type& propertyType = pl[i].getType();
+
+ if (propertyType.isDataType())
+ {
+ SDOXMLString propertyValue = (dataObject->getCString(pl[i]));
+ if (pi && pi->getPropertyDefinition().isQName)
+ {
+ XMLQName qname(propertyValue);
+
+ // TODO: this logic seems bad. We should already have the namespace in the map
+ std::map<SDOXMLString,SDOXMLString>::iterator it = namespaceMap.find(qname.getURI());
+ if (it != namespaceMap.end())
+ {
+ propertyValue = (*it).second + ":" + qname.getLocalName();
+ }
+ else
+ {
+ char buffer[20];
+ SDOXMLString pref = "tnss";
+ sprintf(buffer, "%d", j++);
+ pref += buffer;
+ rc = xmlTextWriterWriteAttributeNS(writer, s_xmlns, pref, NULL, qname.getURI());
+ propertyValue = pref + ":" + qname.getLocalName();
+ }
+
+ }
+ rc = xmlTextWriterWriteAttribute(writer,
+ propertyName, propertyValue);
+ }
+ else
+ {
+ // Handle non-containment reference to DataObject
+ if (pl[i].isReference())
+ {
+ writeReference(propertyName, dataObject, pl[i], false);
+ }
+ }
+ }
+ }
+ // End - attributes are written
+ // ----------------------------
+
+
+ // --------------------
+ // Handle ChangeSummary
+ if (dataObject->getType().isChangeSummaryType())
+ {
+ ChangeSummaryPtr changeSummary = dataObject->getChangeSummary();
+ if (changeSummary)
+ {
+ handleChangeSummary(elementName, changeSummary);
+ }
+ }
+ // End - ChangeSummary is written
+ // ------------------------------
+
+
+ // --------------------
+ // Write Sequenced Data
+ if (dataObjectType.isSequencedType())
+ {
+ SequencePtr sequence = dataObject->getSequence();
+ if (sequence)
+ {
+ for (i=0; i<sequence->size(); i++)
+ {
+ if (sequence->isText(i))
+ {
+ // This is a raw write rather than xmlTextWriterWriteString
+ // just in case the text has a CDATA section in it
+ rc = xmlTextWriterWriteRaw(
+ writer,
+ SDOXMLString(sequence->getCStringValue(i)));
+ continue;
+ } // end TextType
+
+ const Property& seqProp = sequence->getProperty(i);
+ const Type& seqPropType = seqProp.getType();
+ SDOXMLString seqPropName;
+ SDOXMLString seqPropURI;
+
+ // This call sets the property name and type URI and returns if xsi:type= is required
+ bool xsiTypeNeeded = determineNamespace(dataObject, seqProp, seqPropURI, seqPropName);
+
+ // Do not write attributes as members of the sequence
+ XSDPropertyInfo* pi = getPropertyInfo(seqProp);
+ PropertyDefinitionImpl propdef;
+ if (pi)
+ {
+ propdef = pi->getPropertyDefinition();
+ if (!(propdef.isElement))
+ {
+ continue;
+ }
+ }
+
+
+ if (seqPropType.isDataObjectType())
+ {
+ DataObjectPtr doValue = sequence->getDataObjectValue(i);
+
+ if (doValue)
+ {
+ // Handle non-containment reference to DataObject
+ if (seqProp.isReference())
+ {
+ writeReference(seqPropName, dataObject, seqProp, true, doValue);
+ }
+ else
+ {
+ // If property is an undeclared propery of an open type
+ // we write xsi:type
+ bool xsiTypeNeeded = false;
+ if (isOpen)
+ {
+ if (typeImpl.getPropertyImpl(seqPropName) == 0)
+ {
+ xsiTypeNeeded = true;
+ }
+ }
+
+ writeDO(doValue, seqPropURI, seqPropName, xsiTypeNeeded);
+ }
+ }
+ } // end DataObject
+
+ else
+ {
+ // Sequence member is a primitive
+ // Only write a primitive as an element if defined by the schema or if it's
+ // many-valued.
+ if (!pi && !seqProp.isMany()) continue;
+
+ // Write the startElement for non-root object
+ SDOXMLString theName=seqPropName;
+
+ if (!seqPropURI.isNull()
+ && !seqPropURI.equals("")
+ && !seqPropURI.equals(s_commonjsdo))
+ {
+ // Locate the namespace prefix
+ std::map<SDOXMLString,SDOXMLString>::iterator it = namespaceMap.find(seqPropURI);
+ if (it != namespaceMap.end())
+ {
+ theName = (*it).second;
+ theName += ":";
+ theName += seqPropName;
+ }
+ }
+ xmlTextWriterStartElement(writer, theName);
+
+ /* Use our wrapper function just in case the element has CDATA in it */
+ writeXMLElement(writer,
+ seqPropName,
+ sequence->getCStringValue(i));
+ xmlTextWriterEndElement(writer);
+
+ } // end DataType
+ } // end - iterate over sequence
+
+ }
+ }
+ // End = sequenced data is written
+ // -------------------------------
+
+
+ // ------------------------
+ // Non-sequenced DataObject
+ else
+ {
+ // Write elements for this DataObject
+
+ PropertyList definedProps = dataObjectType.getProperties();
+ unsigned int nDefinedProps = typeImpl.getPropertiesSize();
+ unsigned int nOpenProps = pl.size() - nDefinedProps;
+ unsigned int openPropIndex = nDefinedProps;
+
+ const TypeImpl* doTypeImpl = &typeImpl;
+ if (nOpenProps != 0)
+ {
+ while(doTypeImpl->isOpenTypeImplicitly())
+ {
+ doTypeImpl = doTypeImpl->getBaseTypeImpl();
+ }
+ openPropIndex = doTypeImpl->getPropertiesSize();
+ }
+
+ writeDOElements(dataObject, pl, 0, openPropIndex);
+ writeDOElements(dataObject, pl, nDefinedProps, nOpenProps );
+ writeDOElements(dataObject, pl, openPropIndex, nDefinedProps - openPropIndex);
+
+ }
+ // End - non-sequenced DO
+ // ----------------------
+
+ rc = xmlTextWriterEndElement(writer);
+ return rc;
+
+ } // End - writeDO
+
+ void SDOXMLWriter::writeDOElements(DataObjectPtr dataObject,
+ const PropertyList& pl,
+ unsigned int start,
+ unsigned int number)
+ {
+ for (unsigned int pi = 0; pi < number; pi++)
+ {
+ unsigned int i = start + pi;
+ if (dataObject->isSet(pl[i]))
+ {
+ SDOXMLString propertyName;
+ SDOXMLString propertyTypeURI;
+
+ // This call sets the property name and type URI and returns if xsi:type= is required
+ bool xsiTypeNeeded = determineNamespace(dataObject, pl[i], propertyTypeURI, propertyName);
+
+ const Type& propertyType = pl[i].getType();
+ XSDPropertyInfo* pi = getPropertyInfo(pl[i]);
+ PropertyDefinitionImpl propdef;
+ if (pi)
+ {
+ propdef = pi->getPropertyDefinition();
+ if (!(propdef.isElement))
+ {
+ continue;
+ }
+ }
+
+ // -------------------------------------------------
+ // For a many-valued property get the list of values
+ if (pl[i].isMany())
+ {
+ DataObjectList& dol = dataObject->getList(pl[i]);
+ for (unsigned int j = 0; j <dol.size(); j++)
+ {
+ // Handle non-containment reference to DataObject
+ if (pl[i].isReference() )
+ {
+ writeReference(propertyName, dataObject, pl[i], true, dol[j]);
+ }
+ else
+ {
+ writeDO(dol[j], propertyTypeURI, propertyName, xsiTypeNeeded);
+ }
+ }
+ }
+ // End - write many valued property
+ // --------------------------------
+
+
+ // -----------------------------
+ // For a dataobject write the do
+ else if (!propertyType.isDataType())
+ {
+ // Handle non-containment reference to DataObject
+ if (pl[i].isReference())
+ {
+ if (pi)
+ writeReference(propertyName, dataObject, pl[i], true);
+ }
+ else
+ {
+ DataObjectPtr propDO = dataObject->getDataObject(pl[i]);
+ writeDO(propDO, propertyTypeURI, propertyName, xsiTypeNeeded);
+ }
+ }
+ // End - write DataObject
+ // ----------------------
+
+
+ // ---------------
+ // For a primitive
+ else
+ {
+ // Only write a primitive as an element if defined by the XSD
+ if (pi)
+ {
+ const Type& tp = dataObject->getType();
+ XSDTypeInfo* typeInfo = (XSDTypeInfo*)
+ ((DASType*)&tp)->getDASValue("XMLDAS::TypeInfo");
+ if (typeInfo && typeInfo->getTypeDefinition().isExtendedPrimitive)
+ {
+ xmlTextWriterWriteRaw(
+ writer,
+ SDOXMLString(dataObject->getCString(pl[i])));
+ }
+ else
+ {
+ // Write the startElement for non-root object
+ SDOXMLString theName=propertyName;
+
+ if (!propertyTypeURI.isNull()
+ && !propertyTypeURI.equals("")
+ && !propertyTypeURI.equals(s_commonjsdo)
+ /* && !propertyTypeURI.equals(tnsURI) */)
+ {
+ // Locate the namespace prefix
+ std::map<SDOXMLString,SDOXMLString>::iterator it = namespaceMap.find(propertyTypeURI);
+ if (it != namespaceMap.end())
+ {
+ theName = (*it).second;
+ theName += ":";
+ theName += propertyName;
+ }
+ }
+
+ xmlTextWriterStartElement(writer, theName);
+
+ //xmlTextWriterStartElementNS(writer, NULL, propertyName, NULL);
+ if (dataObject->isNull(pl[i]))
+ {
+ xmlTextWriterWriteAttributeNS(writer, s_xsi, s_nil, NULL, s_true);
+ }
+ else
+ {
+ writeXMLElement(writer,
+ propertyName,
+ dataObject->getCString(pl[i]));
+ }
+ xmlTextWriterEndElement(writer);
+ }
+ }
+ }
+ // End - handle primitive
+ // ----------------------
+
+ } // end isSet
+ }
+ // End - elements are written
+ // --------------------------
+
+ }
+
+ XSDPropertyInfo* SDOXMLWriter::getPropertyInfo(const Property& property)
+ {
+ return (XSDPropertyInfo*)((DASProperty*)&property)->getDASValue("XMLDAS::PropertyInfo");
+ }
+
+
+ void SDOXMLWriter::writeReference(
+ const SDOXMLString& propertyName,
+ DataObjectPtr dataObject,
+ const Property& property,
+ bool isElement,
+ DataObjectPtr refferedToObject)
+ {
+ DataObjectPtr reffedObject = refferedToObject;
+ if (reffedObject == 0)
+ {
+ reffedObject = dataObject->getDataObject(property);
+ }
+
+ // Get ID from referred to DataObject or use XPath
+ SDOXMLString refValue;
+ XSDTypeInfo* ti = (XSDTypeInfo*)((DASType*)&reffedObject->getType())->
+ getDASValue("XMLDAS::TypeInfo");
+ if (ti)
+ {
+ TypeDefinitionImpl typeDef = ti->getTypeDefinition();
+ if (!typeDef.IDPropertyName.isNull())
+ {
+ refValue = reffedObject->getCString((const char*)typeDef.IDPropertyName);
+ }
+ }
+
+ if (refValue.isNull())
+ {
+ // need to get XPATH
+ refValue = ((DataObjectImpl*)(DataObject*)reffedObject)->objectToXPath();
+ }
+
+ if (!refValue.isNull())
+ {
+ if (isElement)
+ {
+ // Set the IDREF value
+ xmlTextWriterWriteElement(writer,
+ propertyName, refValue);
+ }
+ else
+ {
+ // Set the IDREF value
+ xmlTextWriterWriteAttribute(writer,
+ propertyName, refValue);
+ }
+ }
+ }
+
+
+
+ /**
+ * A wrapper for the libxml2 function xmlTextWriterWriteElement
+ * it detects CDATA sections before writing out element contents
+ */
+ int SDOXMLWriter::writeXMLElement(xmlTextWriterPtr writer,
+ const SDOXMLString& name,
+ const SDOXMLString& content)
+ {
+ int rc = 0;
+ rc = xmlTextWriterWriteRaw(writer, SDOXMLString(SDOUtils::escapeHtmlEntitiesExcludingCData(content).c_str()));
+
+ /* A more complex version that doesn't work!
+ * I've left it here just in case we need to go back and separate out
+ * CDATA from text. This might provide a starting point
+ SDOString contentString(content);
+
+ // write the start of the element. we could write a mixture of
+ // text and CDATA before writing the end element
+ rc = xmlTextWriterStartElement(writer, name);
+
+ // Iterate along the string writing out text and CDATA sections
+ // separately using the appropriate libxml2 calls
+ std::string::size_type start = 0;
+ std::string::size_type end = contentString.find(PropertySetting::XMLCDataStartMarker, 0);
+ std::string::size_type length = 0;
+
+ // loop while we still find a CDATA section that needs writing
+ while ( end != std::string::npos )
+ {
+ // write out text from current pos to start of CDATA section
+ length = end - start;
+ rc = xmlTextWriterWriteString(writer,
+ SDOXMLString(contentString.substr(start, length).c_str()));
+
+ // find the end of the CDATA section
+ start = end;
+ end = contentString.find(PropertySetting::XMLCDataEndMarker, start);
+
+ if ( end != std::string::npos )
+ {
+ // we only nudge the start marker on to the end of the CDATA marker here
+ // so that if we fail to find the end CDATA marker the whole string gets
+ // printed out by virtue of the line that follows the while loop
+ start = start + strlen(PropertySetting::XMLCDataStartMarker);
+
+ // write our the text from the CDATA section
+ length = end - start;
+ rc = xmlTextWriterWriteCDATA(writer,
+ SDOXMLString(contentString.substr(start, length).c_str()));
+
+ // set current pos to end of CDATA section and
+ // start looking for the start marker again
+ start = end + strlen(PropertySetting::XMLCDataEndMarker);
+ end = contentString.find(PropertySetting::XMLCDataStartMarker, start);
+ }
+ }
+
+ // write out text following the last CDATA section
+ rc = xmlTextWriterWriteString(writer,
+ SDOXMLString(contentString.substr(start).c_str()));
+
+ // close off the element
+ rc = xmlTextWriterEndElement(writer);
+ */
+ return rc;
+ }
+
+ bool SDOXMLWriter::determineNamespace(DataObjectPtr dataObject, const Property& prop,
+ SDOXMLString& elementURI, SDOXMLString& elementName)
+ {
+ bool xsiTypeNeeded = false;
+
+ const Type& propertyType = prop.getType();
+
+ // If this is a defined property with property information
+ // we use the uri and name from the definition
+ XSDPropertyInfo* pi = getPropertyInfo(prop);
+ PropertyDefinitionImpl propdef;
+ if (pi)
+ {
+ propdef = pi->getPropertyDefinition();
+ elementName = propdef.localname;
+ elementURI = propdef.namespaceURI;
+ }
+ else
+ {
+ elementName = prop.getName();
+
+ SDOXMLString propTypeName = propertyType.getName();
+ SDOXMLString propTypeURI = propertyType.getURI();
+ DataObjectImpl* dataObjectImpl = (DataObjectImpl*)(DataObject*)dataObject;
+ const TypeImpl& typeImpl = dataObjectImpl->getTypeImpl();
+
+
+ // If property is an undeclared propery of an open type
+ if (typeImpl.getPropertyImpl(prop.getName()) == 0)
+ {
+ // we need to write xsi:type information
+ xsiTypeNeeded = true;
+
+ // Determine the namespace of the property
+ // First see if there is a matching property in the namespace
+ // of the Type of this property.
+ DataFactoryImpl* df = (DataFactoryImpl*)dataObject->getDataFactory();
+ const TypeImpl* ti = df->findTypeImpl(propertyType.getURI(), "RootType");
+ if (ti)
+ {
+ PropertyImpl* propi = ti->getPropertyImpl(elementName);
+ if (propi)
+ {
+ SDOXMLString propiTypeName = propi->getType().getName();
+ SDOXMLString propiTypeURI = propi->getType().getURI();
+ if (propiTypeName.equals(propTypeName)
+ && propiTypeURI.equals(propTypeURI) )
+ {
+ // We have a match
+
+ // it's a global element so we do not need xsi:type
+ xsiTypeNeeded = false;
+
+ XSDPropertyInfo* ppi = getPropertyInfo(*propi);
+ PropertyDefinitionImpl propdef;
+ if (ppi)
+ {
+ propdef = ppi->getPropertyDefinition();
+ elementName = propdef.localname;
+ elementURI = propdef.namespaceURI;
+ }
+ }
+ }
+ }
+ else
+ {
+ // For now we will just set the elementURI to ""
+ // We need to check further here for the element defined in
+ // the namespace of the parent object etc. etc.
+ elementURI = "";
+ }
+ }
+ else
+ {
+ // The property has been defined programatically so we will
+ // assume elementForm is "unqualified"
+ elementURI = "";
+ }
+
+ }
+
+ if (propertyType.isAbstractType())
+ {
+ xsiTypeNeeded = true;
+ }
+
+ return xsiTypeNeeded;
+
+ }
+
+ } // End - namespace sdo
+} // End - namespace commonj
+
+