/* * 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 { using internal::XSDPropertyInfo; using internal::PropertyDefinitionImpl; using internal::XSDTypeInfo; using internal::TypeDefinitionImpl; using internal::SDOUtils; 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;igetXMLDeclaration()) { rc = xmlTextWriterStartDocument(writer, doc->getXMLVersion(), doc->getEncoding(), NULL); if (rc < 0) { throw SDOXMLParserException(TUSCANY_SDO_EINFO, "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) { throw SDOXMLParserException(TUSCANY_SDO_EINFO, "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(staticCast(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(staticCast(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 = getRawPointer(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 = ((DataObjectImpl*)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(SDOUtils::sdoURI)); 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(staticCast(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::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::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*)getRawPointer(dl[k]); if (d != 0)addToNamespaces(d); } } } else { if (!pl[i].getType().isDataType()) { DataObjectImpl* d = (DataObjectImpl*)getRawPointer(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*)getRawPointer(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*)getRawPointer(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::iterator it = namespaceMap.find(elementURI); if (it != namespaceMap.end()) { theName = (*it).second; theName += ":"; theName += elementName; } } rc = xmlTextWriterStartElement(writer, theName); if (rc < 0) { throw SDOXMLParserException(TUSCANY_SDO_EINFO, "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::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::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 if (propdef.isElement) continue; // Many-valued properties are written as 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::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; isize(); 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::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 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::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*)getRawPointer(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, content); /* 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*)getRawPointer(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. DataFactoryImplPtr df = staticCast(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