// Start a snapshot at the root object, using supplied namespace manager. public XmlSnapshot(object obj, XmlSchema schema) { INakedObject rootObject = PersistorUtils.CreateAdapter(obj); Log.Debug(".ctor(" + DoLog("rootObj", rootObject) + AndLog("schema", schema) + AndLog("addOids", "" + true) + ")"); Schema = schema; try { XmlDocument = new XDocument(); XsdDocument = new XDocument(); XsdElement = XsMetaModel.CreateXsSchemaElement(XsdDocument); rootPlace = AppendXml(rootObject); } catch (ArgumentException e) { Log.Error("unable to build snapshot", e); throw new NakedObjectSystemException(e); } }
// Start a snapshot at the root object, using supplied namespace manager. public XmlSnapshot(object obj, XmlSchema schema, INakedObjectManager nakedObjectManager, IMetamodelManager metamodelManager) { this.nakedObjectManager = nakedObjectManager; this.metamodelManager = metamodelManager; INakedObjectAdapter rootObjectAdapter = nakedObjectManager.CreateAdapter(obj, null, null); Schema = schema; try { XmlDocument = new XDocument(); XsdDocument = new XDocument(); XsdElement = XsMetaModel.CreateXsSchemaElement(XsdDocument); rootPlace = AppendXml(rootObjectAdapter); } catch (ArgumentException e) { throw new NakedObjectSystemException(Log.LogAndReturn("Unable to build snapshot"), e); } }
// Start a snapshot at the root object, using supplied namespace manager. public XmlSnapshot(object obj, XmlSchema schema, INakedObjectManager nakedObjectManager, IMetamodelManager metamodelManager) { this.nakedObjectManager = nakedObjectManager; this.metamodelManager = metamodelManager; INakedObjectAdapter rootObjectAdapter = nakedObjectManager.CreateAdapter(obj, null, null); Log.Debug(".ctor(" + DoLog("rootObj", rootObjectAdapter) + AndLog("schema", schema) + AndLog("addOids", "" + true) + ")"); Schema = schema; try { XmlDocument = new XDocument(); XsdDocument = new XDocument(); XsdElement = XsMetaModel.CreateXsSchemaElement(XsdDocument); rootPlace = AppendXml(rootObjectAdapter); } catch (ArgumentException e) { Log.Error("unable to build snapshot", e); throw new NakedObjectSystemException(e); } }
public Place ObjectToElement(INakedObjectAdapter nakedObjectAdapter) { Log.Debug("objectToElement(" + DoLog("object", nakedObjectAdapter) + ")"); var nos = (IObjectSpec) nakedObjectAdapter.Spec; Log.Debug("objectToElement(NO): create element and nof:title"); XElement element = Schema.CreateElement(XmlDocument, nos.ShortName, nos.FullName, nos.SingularName, nos.PluralName); NofMetaModel.AppendNofTitle(element, nakedObjectAdapter.TitleString()); Log.Debug("objectToElement(NO): create XS element for NOF class"); XElement xsElement = Schema.CreateXsElementForNofClass(XsdDocument, element, topLevelElementWritten); // hack: every element in the XSD schema apart from first needs minimum cardinality setting. topLevelElementWritten = true; var place = new Place(nakedObjectAdapter, element); NofMetaModel.SetAttributesForClass(element, OidOrHashCode(nakedObjectAdapter)); IAssociationSpec[] fields = nos.Properties; Log.Debug("objectToElement(NO): processing fields"); var seenFields = new List<string>(); foreach (IAssociationSpec field in fields) { string fieldName = field.Id; Log.Debug("objectToElement(NO): " + DoLog("field", fieldName)); // Skip field if we have seen the name already // This is a workaround for getLastActivity(). This method exists // in AbstractNakedObject, but is not (at some level) being picked up // by the dot-net reflector as a property. On the other hand it does // exist as a field in the meta model (NakedObjectSpecification). // // Now, to re-expose the lastactivity field for .Net, a deriveLastActivity() // has been added to BusinessObject. This caused another field ofthe // same name, ultimately breaking the XSD. if (seenFields.Contains(fieldName)) { Log.Debug("objectToElement(NO): " + DoLog("field", fieldName) + " SKIPPED"); continue; } seenFields.Add(fieldName); XNamespace ns = Schema.GetUri(); var xmlFieldElement = new XElement(ns + fieldName); XElement xsdFieldElement; var oneToOneAssociation = field as IOneToOneAssociationSpec; var oneToManyAssociation = field as IOneToManyAssociationSpec; if (field.ReturnSpec.IsParseable && oneToOneAssociation != null) { Log.Debug("objectToElement(NO): " + DoLog("field", fieldName) + " is value"); IObjectSpec fieldNos = field.ReturnSpec; // skip fields of type XmlValue if (fieldNos != null && fieldNos.FullName != null && fieldNos.FullName.EndsWith("XmlValue")) { continue; } XElement xmlValueElement = xmlFieldElement; // more meaningful locally scoped name try { INakedObjectAdapter value = oneToOneAssociation.GetNakedObject(nakedObjectAdapter); // a null value would be a programming error, but we protect // against it anyway if (value == null) { continue; } ITypeSpec valueNos = value.Spec; // XML NofMetaModel.SetAttributesForValue(xmlValueElement, valueNos.ShortName); bool notEmpty = (value.TitleString().Length > 0); if (notEmpty) { string valueStr = value.TitleString(); xmlValueElement.Add(new XText(valueStr)); } else { NofMetaModel.SetIsEmptyAttribute(xmlValueElement, true); } } catch (Exception) { Log.Warn("objectToElement(NO): " + DoLog("field", fieldName) + ": getField() threw exception - skipping XML generation"); } // XSD xsdFieldElement = Schema.CreateXsElementForNofValue(xsElement, xmlValueElement); } else if (oneToOneAssociation != null) { Log.Debug("objectToElement(NO): " + DoLog("field", fieldName) + " is IOneToOneAssociation"); XElement xmlReferenceElement = xmlFieldElement; // more meaningful locally scoped name try { INakedObjectAdapter referencedNakedObjectAdapter = oneToOneAssociation.GetNakedObject(nakedObjectAdapter); string fullyQualifiedClassName = field.ReturnSpec.FullName; // XML NofMetaModel.SetAttributesForReference(xmlReferenceElement, Schema.Prefix, fullyQualifiedClassName); if (referencedNakedObjectAdapter != null) { NofMetaModel.AppendNofTitle(xmlReferenceElement, referencedNakedObjectAdapter.TitleString()); } else { NofMetaModel.SetIsEmptyAttribute(xmlReferenceElement, true); } } catch (Exception) { Log.Warn("objectToElement(NO): " + DoLog("field", fieldName) + ": getAssociation() threw exception - skipping XML generation"); } // XSD xsdFieldElement = Schema.CreateXsElementForNofReference(xsElement, xmlReferenceElement, oneToOneAssociation.ReturnSpec.FullName); } else if (oneToManyAssociation != null) { Log.Debug("objectToElement(NO): " + DoLog("field", fieldName) + " is IOneToManyAssociation"); XElement xmlCollectionElement = xmlFieldElement; // more meaningful locally scoped name try { INakedObjectAdapter collection = oneToManyAssociation.GetNakedObject(nakedObjectAdapter); ITypeOfFacet facet = collection.GetTypeOfFacetFromSpec(); IObjectSpecImmutable referencedTypeNos = facet.GetValueSpec(collection, metamodelManager.Metamodel); string fullyQualifiedClassName = referencedTypeNos.FullName; // XML NofMetaModel.SetNofCollection(xmlCollectionElement, Schema.Prefix, fullyQualifiedClassName, collection, nakedObjectManager); } catch (Exception) { Log.Warn("objectToElement(NO): " + DoLog("field", fieldName) + ": get(obj) threw exception - skipping XML generation"); } // XSD xsdFieldElement = Schema.CreateXsElementForNofCollection(xsElement, xmlCollectionElement, oneToManyAssociation.ReturnSpec.FullName); } else { Log.Info("objectToElement(NO): " + DoLog("field", fieldName) + " is unknown type; ignored"); continue; } if (xsdFieldElement != null) { xmlFieldElement.AddAnnotation(xsdFieldElement); } // XML Log.Debug("objectToElement(NO): invoking mergeTree for field"); MergeTree(element, xmlFieldElement); // XSD if (xsdFieldElement != null) { Log.Debug("objectToElement(NO): adding XS element for field to schema"); Schema.AddFieldXsElement(xsElement, xsdFieldElement); } } return place; }
// return true if able to navigate the complete vector of field names // successfully; false if a field could not be located or it turned // out to be a value. private bool IncludeField(Place place, IList<string> fieldNames, string annotation) { Log.DebugFormat("includeField(: {0})", DoLog("place", place) + AndLog("fieldNames", fieldNames) + AndLog("annotation", annotation)); INakedObjectAdapter nakedObjectAdapter = place.NakedObjectAdapter; XElement xmlElement = place.XmlElement; // we use a copy of the path so that we can safely traverse collections // without side-effects fieldNames = fieldNames.ToList(); // see if we have any fields to process if (!fieldNames.Any()) { return true; } // take the first field name from the list, and remove string fieldName = fieldNames.First(); fieldNames.Remove(fieldName); Log.Debug("includeField(Pl, Vec, Str):" + DoLog("processing field", fieldName) + AndLog("left", "" + fieldNames.Count())); // locate the field in the object's class var nos = (IObjectSpec) nakedObjectAdapter.Spec; IAssociationSpec field = nos.Properties.SingleOrDefault(p => p.Id.ToLower() == fieldName); if (field == null) { Log.Info("includeField(Pl, Vec, Str): could not locate field, skipping"); return false; } // locate the corresponding XML element // (the corresponding XSD element will later be attached to xmlElement // as its userData) Log.Debug("includeField(Pl, Vec, Str): locating corresponding XML element"); XElement[] xmlFieldElements = ElementsUnder(xmlElement, field.Id).ToArray(); int fieldCount = xmlFieldElements.Count(); if (fieldCount != 1) { Log.Info("includeField(Pl, Vec, Str): could not locate " + DoLog("field", field.Id) + AndLog("xmlFieldElements.size", "" + fieldCount)); return false; } XElement xmlFieldElement = xmlFieldElements.First(); if (!fieldNames.Any() && annotation != null) { // nothing left in the path, so we will apply the annotation now NofMetaModel.SetAnnotationAttribute(xmlFieldElement, annotation); } var fieldPlace = new Place(nakedObjectAdapter, xmlFieldElement); if (field.ReturnSpec.IsParseable) { Log.Debug("includeField(Pl, Vec, Str): field is value; done"); return false; } var oneToOneAssociation = field as IOneToOneAssociationSpec; if (oneToOneAssociation != null) { Log.Debug("includeField(Pl, Vec, Str): field is 1->1"); INakedObjectAdapter referencedObjectAdapter = oneToOneAssociation.GetNakedObject(fieldPlace.NakedObjectAdapter); if (referencedObjectAdapter == null) { return true; // not a failure if the reference was null } bool appendedXml = AppendXmlThenIncludeRemaining(fieldPlace, referencedObjectAdapter, fieldNames, annotation); Log.Debug("includeField(Pl, Vec, Str): 1->1: invoked appendXmlThenIncludeRemaining for " + DoLog("referencedObj", referencedObjectAdapter) + AndLog("returned", "" + appendedXml)); return appendedXml; } var oneToManyAssociation = field as IOneToManyAssociationSpec; if (oneToManyAssociation != null) { Log.Debug("includeField(Pl, Vec, Str): field is 1->M"); INakedObjectAdapter collection = oneToManyAssociation.GetNakedObject(fieldPlace.NakedObjectAdapter); INakedObjectAdapter[] collectionAsEnumerable = collection.GetAsEnumerable(nakedObjectManager).ToArray(); Log.Debug("includeField(Pl, Vec, Str): 1->M: " + DoLog("collection.size", "" + collectionAsEnumerable.Count())); bool allFieldsNavigated = true; foreach (INakedObjectAdapter referencedObject in collectionAsEnumerable) { bool appendedXml = AppendXmlThenIncludeRemaining(fieldPlace, referencedObject, fieldNames, annotation); Log.Debug("includeField(Pl, Vec, Str): 1->M: + invoked appendXmlThenIncludeRemaining for " + DoLog("referencedObj", referencedObject) + AndLog("returned", "" + appendedXml)); allFieldsNavigated = allFieldsNavigated && appendedXml; } Log.Debug("includeField(Pl, Vec, Str): " + DoLog("returning", "" + allFieldsNavigated)); return allFieldsNavigated; } return false; // fall through, shouldn't get here but just in case. }
private bool AppendXmlThenIncludeRemaining(Place parentPlace, INakedObjectAdapter referencedObjectAdapter, IList<string> fieldNames, string annotation) { Log.Debug("appendXmlThenIncludeRemaining(: " + DoLog("parentPlace", parentPlace) + AndLog("referencedObj", referencedObjectAdapter) + AndLog("fieldNames", fieldNames) + AndLog("annotation", annotation) + ")"); Log.Debug("appendXmlThenIncludeRemaining(..): invoking appendXml(parentPlace, referencedObjectAdapter)"); XElement referencedElement = AppendXml(parentPlace, referencedObjectAdapter); var referencedPlace = new Place(referencedObjectAdapter, referencedElement); bool includedField = IncludeField(referencedPlace, fieldNames, annotation); Log.Debug("appendXmlThenIncludeRemaining(..): invoked includeField(referencedPlace, fieldNames)" + AndLog("returned", "" + includedField)); return includedField; }
// Creates an XElement representing this object, and appends it to the // supplied parentElement, provided that an element for the object is not // already appended. // // The method uses the OID to determine if an object's element is already // present. If the object is not yet persistent, then the hashCode is used // instead. // // The parentElement must have an owner document, and should define the nof // namespace. Additionally, the supplied schemaManager must be populated // with any application-level namespaces referenced in the document that the // parentElement resides within. (Normally this is achieved simply by using // appendXml passing in a rootElement and a new schemaManager - see // ToXml() or XmlSnapshot). private XElement AppendXml(Place parentPlace, INakedObjectAdapter childObjectAdapter) { Log.Debug("appendXml(" + DoLog("parentPlace", parentPlace) + AndLog("childObj", childObjectAdapter) + ")"); XElement parentElement = parentPlace.XmlElement; var parentXsElement = parentElement.Annotation<XElement>(); if (parentElement.Document != XmlDocument) { throw new ArgumentException("parent XML XElement must have snapshot's XML document as its owner"); } Log.Debug("appendXml(Pl, NO): invoking objectToElement() for " + DoLog("childObj", childObjectAdapter)); Place childPlace = ObjectToElement(childObjectAdapter); XElement childElement = childPlace.XmlElement; var childXsElement = childElement.Annotation<XElement>(); Log.Debug("appendXml(Pl, NO): invoking mergeTree of parent with child"); childElement = MergeTree(parentElement, childElement); Log.Debug("appendXml(Pl, NO): adding XS XElement to schema if required"); Schema.AddXsElementIfNotPresent(parentXsElement, childXsElement); return childElement; }
// return true if able to navigate the complete vector of field names // successfully; false if a field could not be located or it turned // out to be a value. private bool IncludeField(Place place, IList<string> fieldNames, string annotation) { INakedObjectAdapter nakedObjectAdapter = place.NakedObjectAdapter; XElement xmlElement = place.XmlElement; // we use a copy of the path so that we can safely traverse collections // without side-effects fieldNames = fieldNames.ToList(); // see if we have any fields to process if (!fieldNames.Any()) { return true; } // take the first field name from the list, and remove string fieldName = fieldNames.First(); fieldNames.Remove(fieldName); // locate the field in the object's class var nos = (IObjectSpec) nakedObjectAdapter.Spec; IAssociationSpec field = nos.Properties.SingleOrDefault(p => p.Id.ToLower() == fieldName); if (field == null) { return false; } // locate the corresponding XML element // (the corresponding XSD element will later be attached to xmlElement // as its userData) XElement[] xmlFieldElements = ElementsUnder(xmlElement, field.Id).ToArray(); int fieldCount = xmlFieldElements.Length; if (fieldCount != 1) { return false; } XElement xmlFieldElement = xmlFieldElements.First(); if (!fieldNames.Any() && annotation != null) { // nothing left in the path, so we will apply the annotation now NofMetaModel.SetAnnotationAttribute(xmlFieldElement, annotation); } var fieldPlace = new Place(nakedObjectAdapter, xmlFieldElement); if (field.ReturnSpec.IsParseable) { return false; } var oneToOneAssociation = field as IOneToOneAssociationSpec; if (oneToOneAssociation != null) { INakedObjectAdapter referencedObjectAdapter = oneToOneAssociation.GetNakedObject(fieldPlace.NakedObjectAdapter); if (referencedObjectAdapter == null) { return true; // not a failure if the reference was null } bool appendedXml = AppendXmlThenIncludeRemaining(fieldPlace, referencedObjectAdapter, fieldNames, annotation); return appendedXml; } var oneToManyAssociation = field as IOneToManyAssociationSpec; if (oneToManyAssociation != null) { INakedObjectAdapter collection = oneToManyAssociation.GetNakedObject(fieldPlace.NakedObjectAdapter); INakedObjectAdapter[] collectionAsEnumerable = collection.GetAsEnumerable(nakedObjectManager).ToArray(); bool allFieldsNavigated = true; foreach (INakedObjectAdapter referencedObject in collectionAsEnumerable) { bool appendedXml = AppendXmlThenIncludeRemaining(fieldPlace, referencedObject, fieldNames, annotation); allFieldsNavigated = allFieldsNavigated && appendedXml; } return allFieldsNavigated; } return false; // fall through, shouldn't get here but just in case. }
private bool AppendXmlThenIncludeRemaining(Place parentPlace, INakedObjectAdapter referencedObjectAdapter, IList<string> fieldNames, string annotation) { XElement referencedElement = AppendXml(parentPlace, referencedObjectAdapter); var referencedPlace = new Place(referencedObjectAdapter, referencedElement); bool includedField = IncludeField(referencedPlace, fieldNames, annotation); return includedField; }
// Creates an XElement representing this object, and appends it to the // supplied parentElement, provided that an element for the object is not // already appended. // // The method uses the OID to determine if an object's element is already // present. If the object is not yet persistent, then the hashCode is used // instead. // // The parentElement must have an owner document, and should define the nof // namespace. Additionally, the supplied schemaManager must be populated // with any application-level namespaces referenced in the document that the // parentElement resides within. (Normally this is achieved simply by using // appendXml passing in a rootElement and a new schemaManager - see // ToXml() or XmlSnapshot). private XElement AppendXml(Place parentPlace, INakedObjectAdapter childObjectAdapter) { XElement parentElement = parentPlace.XmlElement; var parentXsElement = parentElement.Annotation<XElement>(); if (parentElement.Document != XmlDocument) { throw new ArgumentException(Log.LogAndReturn("parent XML XElement must have snapshot's XML document as its owner")); } Place childPlace = ObjectToElement(childObjectAdapter); XElement childElement = childPlace.XmlElement; var childXsElement = childElement.Annotation<XElement>(); childElement = MergeTree(parentElement, childElement); Schema.AddXsElementIfNotPresent(parentXsElement, childXsElement); return childElement; }
// return true if able to navigate the complete vector of field names // successfully; false if a field could not be located or it turned // out to be a value. private bool IncludeField(Place place, IList<string> fieldNames, string annotation) { LOG.DebugFormat("includeField(: {0})", Log("place", place) + AndLog("fieldNames", fieldNames) + AndLog("annotation", annotation)); INakedObject nakedObject = place.NakedObject; XElement xmlElement = place.XmlElement; // we use a copy of the path so that we can safely traverse collections // without side-effects fieldNames = fieldNames.ToList(); // see if we have any fields to process if (!fieldNames.Any()) { return true; } // take the first field name from the list, and remove string fieldName = fieldNames.First(); fieldNames.Remove(fieldName); LOG.Debug("includeField(Pl, Vec, Str):" + Log("processing field", fieldName) + AndLog("left", "" + fieldNames.Count())); // locate the field in the object's class INakedObjectSpecification nos = nakedObject.Specification; INakedObjectAssociation field = nos.Properties.Where(p => p.Id.ToLower() == fieldName).SingleOrDefault(); if (field == null) { LOG.Info("includeField(Pl, Vec, Str): could not locate field, skipping"); return false; } // locate the corresponding XML element // (the corresponding XSD element will later be attached to xmlElement // as its userData) LOG.Debug("includeField(Pl, Vec, Str): locating corresponding XML element"); IEnumerable<XElement> xmlFieldElements = ElementsUnder(xmlElement, field.Id); if (xmlFieldElements.Count() != 1) { LOG.Info("includeField(Pl, Vec, Str): could not locate " + Log("field", field.Id) + AndLog("xmlFieldElements.size", "" + xmlFieldElements.Count())); return false; } XElement xmlFieldElement = xmlFieldElements.First(); if (!fieldNames.Any() && annotation != null) { // nothing left in the path, so we will apply the annotation now NofMetaModel.SetAnnotationAttribute(xmlFieldElement, annotation); } var fieldPlace = new Place(nakedObject, xmlFieldElement); if (field.Specification.IsParseable) { LOG.Debug("includeField(Pl, Vec, Str): field is value; done"); return false; } if (field is IOneToOneAssociation) { LOG.Debug("includeField(Pl, Vec, Str): field is 1->1"); var oneToOneAssociation = ((IOneToOneAssociation) field); INakedObject referencedObject = oneToOneAssociation.GetNakedObject(fieldPlace.NakedObject); if (referencedObject == null) { return true; // not a failure if the reference was null } bool appendedXml = AppendXmlThenIncludeRemaining(fieldPlace, referencedObject, fieldNames, annotation); LOG.Debug("includeField(Pl, Vec, Str): 1->1: invoked appendXmlThenIncludeRemaining for " + Log("referencedObj", referencedObject) + AndLog("returned", "" + appendedXml)); return appendedXml; } if (field is IOneToManyAssociation) { LOG.Debug("includeField(Pl, Vec, Str): field is 1->M"); var oneToManyAssociation = (IOneToManyAssociation) field; var collection = oneToManyAssociation.GetNakedObject(fieldPlace.NakedObject); var facet = collection.GetCollectionFacetFromSpec(); LOG.Debug("includeField(Pl, Vec, Str): 1->M: " /*+ Log("collection.size", "" + facet.Size(collection))*/); var allFieldsNavigated = true; for (IEnumerator<INakedObject> enumer = facet.AsEnumerable(collection).GetEnumerator(); enumer.MoveNext();) { var referencedObject = enumer.Current; var appendedXml = AppendXmlThenIncludeRemaining(fieldPlace, referencedObject, fieldNames, annotation); LOG.Debug("includeField(Pl, Vec, Str): 1->M: + invoked appendXmlThenIncludeRemaining for " + Log("referencedObj", referencedObject) + AndLog("returned", "" + appendedXml)); allFieldsNavigated = allFieldsNavigated && appendedXml; } LOG.Debug("includeField(Pl, Vec, Str): " + Log("returning", "" + allFieldsNavigated)); return allFieldsNavigated; } return false; // fall through, shouldn't get here but just in case. }
public Place ObjectToElement(INakedObjectAdapter nakedObjectAdapter) { var nos = (IObjectSpec)nakedObjectAdapter.Spec; var element = Schema.CreateElement(XmlDocument, nos.ShortName, nos.FullName, nos.SingularName, nos.PluralName); NofMetaModel.AppendNofTitle(element, nakedObjectAdapter.TitleString()); var xsElement = Schema.CreateXsElementForNofClass(XsdDocument, element, topLevelElementWritten); // hack: every element in the XSD schema apart from first needs minimum cardinality setting. topLevelElementWritten = true; var place = new Place(nakedObjectAdapter, element); NofMetaModel.SetAttributesForClass(element, OidOrHashCode(nakedObjectAdapter)); var fields = nos.Properties; var seenFields = new List <string>(); foreach (var field in fields) { var fieldName = field.Id; // Skip field if we have seen the name already // This is a workaround for getLastActivity(). This method exists // in AbstractNakedObject, but is not (at some level) being picked up // by the dot-net reflector as a property. On the other hand it does // exist as a field in the meta model (NakedObjectSpecification). // // Now, to re-expose the LastActivity field for .Net, a deriveLastActivity() // has been added to BusinessObject. This caused another field of the // same name, ultimately breaking the XSD. if (seenFields.Contains(fieldName)) { continue; } seenFields.Add(fieldName); XNamespace ns = Schema.GetUri(); var xmlFieldElement = new XElement(ns + fieldName); XElement xsdFieldElement; var oneToOneAssociation = field as IOneToOneAssociationSpec; var oneToManyAssociation = field as IOneToManyAssociationSpec; if (field.ReturnSpec.IsParseable && oneToOneAssociation != null) { var fieldNos = field.ReturnSpec; // skip fields of type XmlValue if (fieldNos?.FullName != null && fieldNos.FullName.EndsWith("XmlValue")) { continue; } var xmlValueElement = xmlFieldElement; // more meaningful locally scoped name try { var value = oneToOneAssociation.GetNakedObject(nakedObjectAdapter); // a null value would be a programming error, but we protect // against it anyway if (value == null) { continue; } var valueNos = value.Spec; // XML NofMetaModel.SetAttributesForValue(xmlValueElement, valueNos.ShortName); var notEmpty = value.TitleString().Length > 0; if (notEmpty) { var valueStr = value.TitleString(); xmlValueElement.Add(new XText(valueStr)); } else { NofMetaModel.SetIsEmptyAttribute(xmlValueElement, true); } } catch (Exception) { logger.LogWarning($"objectToElement(NO): {DoLog("field", fieldName)}: getField() threw exception - skipping XML generation"); } // XSD xsdFieldElement = Schema.CreateXsElementForNofValue(xsElement, xmlValueElement); } else if (oneToOneAssociation != null) { var xmlReferenceElement = xmlFieldElement; // more meaningful locally scoped name try { var referencedNakedObjectAdapter = oneToOneAssociation.GetNakedObject(nakedObjectAdapter); var fullyQualifiedClassName = field.ReturnSpec.FullName; // XML NofMetaModel.SetAttributesForReference(xmlReferenceElement, Schema.Prefix, fullyQualifiedClassName); if (referencedNakedObjectAdapter != null) { NofMetaModel.AppendNofTitle(xmlReferenceElement, referencedNakedObjectAdapter.TitleString()); } else { NofMetaModel.SetIsEmptyAttribute(xmlReferenceElement, true); } } catch (Exception) { logger.LogWarning($"objectToElement(NO): {DoLog("field", fieldName)}: getAssociation() threw exception - skipping XML generation"); } // XSD xsdFieldElement = Schema.CreateXsElementForNofReference(xsElement, xmlReferenceElement, oneToOneAssociation.ReturnSpec.FullName); } else if (oneToManyAssociation != null) { var xmlCollectionElement = xmlFieldElement; // more meaningful locally scoped name try { var collection = oneToManyAssociation.GetNakedObject(nakedObjectAdapter); var facet = collection.GetTypeOfFacetFromSpec(); var referencedTypeNos = facet.GetValueSpec(collection, metamodelManager.Metamodel); var fullyQualifiedClassName = referencedTypeNos.FullName; // XML NofMetaModel.SetNofCollection(xmlCollectionElement, Schema.Prefix, fullyQualifiedClassName, collection, nakedObjectManager); } catch (Exception) { logger.LogWarning($"objectToElement(NO): {DoLog("field", fieldName)}: get(obj) threw exception - skipping XML generation"); } // XSD xsdFieldElement = Schema.CreateXsElementForNofCollection(xsElement, xmlCollectionElement, oneToManyAssociation.ReturnSpec.FullName); } else { continue; } if (xsdFieldElement != null) { xmlFieldElement.AddAnnotation(xsdFieldElement); } // XML MergeTree(element, xmlFieldElement); // XSD if (xsdFieldElement != null) { Schema.AddFieldXsElement(xsElement, xsdFieldElement); } } return(place); }
// return true if able to navigate the complete vector of field names // successfully; false if a field could not be located or it turned // out to be a value. private bool IncludeField(Place place, IList <string> fieldNames, string annotation) { var nakedObjectAdapter = place.NakedObjectAdapter; var xmlElement = place.XmlElement; // we use a copy of the path so that we can safely traverse collections // without side-effects fieldNames = fieldNames.ToList(); // see if we have any fields to process if (!fieldNames.Any()) { return(true); } // take the first field name from the list, and remove var fieldName = fieldNames.First(); fieldNames.Remove(fieldName); // locate the field in the object's class var nos = (IObjectSpec)nakedObjectAdapter.Spec; var field = nos.Properties.SingleOrDefault(p => p.Id.ToLower() == fieldName); if (field == null) { return(false); } // locate the corresponding XML element // (the corresponding XSD element will later be attached to xmlElement // as its userData) var xmlFieldElements = ElementsUnder(xmlElement, field.Id).ToArray(); var fieldCount = xmlFieldElements.Length; if (fieldCount != 1) { return(false); } var xmlFieldElement = xmlFieldElements.First(); if (!fieldNames.Any() && annotation != null) { // nothing left in the path, so we will apply the annotation now NofMetaModel.SetAnnotationAttribute(xmlFieldElement, annotation); } var fieldPlace = new Place(nakedObjectAdapter, xmlFieldElement); if (field.ReturnSpec.IsParseable) { return(false); } var oneToOneAssociation = field as IOneToOneAssociationSpec; if (oneToOneAssociation != null) { var referencedObjectAdapter = oneToOneAssociation.GetNakedObject(fieldPlace.NakedObjectAdapter); if (referencedObjectAdapter == null) { return(true); // not a failure if the reference was null } var appendedXml = AppendXmlThenIncludeRemaining(fieldPlace, referencedObjectAdapter, fieldNames, annotation); return(appendedXml); } var oneToManyAssociation = field as IOneToManyAssociationSpec; if (oneToManyAssociation != null) { var collection = oneToManyAssociation.GetNakedObject(fieldPlace.NakedObjectAdapter); var collectionAsEnumerable = collection.GetAsEnumerable(nakedObjectManager).ToArray(); var allFieldsNavigated = true; foreach (var referencedObject in collectionAsEnumerable) { var appendedXml = AppendXmlThenIncludeRemaining(fieldPlace, referencedObject, fieldNames, annotation); allFieldsNavigated = allFieldsNavigated && appendedXml; } return(allFieldsNavigated); } return(false); // fall through, shouldn't get here but just in case. }