/// <summary> /// Deserializes the TypedValue from xml. /// </summary> /// <param name="reader">The reader.</param> /// <param name="target">The target.</param> internal static void FromXml_Impl(XmlReader reader, TypedValue target) { // Current formats: // <TypedValue type="String">Hello</TypedValue> // <TypedValue type="Int32">1234</TypedValue> // <TypedValue type="InlineRelationship" entityRef="true">123<SourceEntityTypeId entityRef="true">456</SourceEntityTypeId></TypedValue> // etc.. // Legacy (pre 1.0) formats: // <TypedValue><Value xsi:type="xsd:int">4</Value><Type xsi:type="Int32Type" /></TypedValue> // <TypedValue> // <Type xsi:type="InlineRelationshipType"> // </Type> // <SourceEntityTypeId>5678</SourceEntityTypeId> // <Value>1234:Not Available;11293:unknown;</Value> // </TypedValue> // etc.. bool typeNameUsesDisplayName = false; string valueString = string.Empty; // Read 'type' attribute string typeName = reader.GetAttribute("type"); if (typeName != null) { typeName = typeName + "Type"; } // Read any content nodes bool rootIsEmpty = reader.IsEmptyElement; int depth = rootIsEmpty ? 0 : 1; bool isLegacyValueElem = false; bool isLegacyTypeElem = false; bool isSourceEntityTypeIdElem = false; reader.Read(); while (depth > 0) { switch (reader.NodeType) { case XmlNodeType.Element: isLegacyValueElem = false; isLegacyTypeElem = false; isSourceEntityTypeIdElem = false; if (depth == 1) { switch (reader.Name) { // Legacy <Value> element case "Value": case "value": // (conditional formatting) isLegacyValueElem = true; break; // Legacy <type> element (conditional formatting) .. type might be in text or name attribute. case "type": isLegacyTypeElem = true; if (typeName == null) { typeName = reader.GetAttribute("name"); if (typeName != null) { typeNameUsesDisplayName = true; } } break; // Legacy <Type> element case "Type": if (typeName == null) { typeName = reader.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance"); // xsi:type } break; // Deprecated <SourceEntityTypeId> element case "SourceEntityTypeId": // deprecated isSourceEntityTypeIdElem = true; break; } } if (!reader.IsEmptyElement) { depth++; } break; case XmlNodeType.Text: if (!string.IsNullOrEmpty(reader.Value)) { // Depth == 1 : Current Value as Text // Also, legacy Value element if (depth == 1 || isLegacyValueElem) { valueString = reader.Value; } // SourceEntityTypeId element (current) else if (isSourceEntityTypeIdElem) { target.SourceEntityTypeId = XmlConvert.ToInt64(reader.Value); } // Legacy Type element else if (isLegacyTypeElem && typeName == null) { typeName = reader.Value; typeNameUsesDisplayName = true; } } break; case XmlNodeType.EndElement: depth--; break; case XmlNodeType.None: throw new Exception("Unexpected end of XML."); } reader.Read(); } // Validate type if (typeName == null) { throw new InvalidOperationException("No type data"); } // Perform value-string corrections to legacy (pre 1.0) format. if (typeName == "ChoiceRelationshipType" || typeName == "InlineRelationshipType" || typeName == "IdentifierType") { if (valueString.EndsWith(";")) { valueString = valueString.Split(':')[0]; } } if (typeNameUsesDisplayName) { // Legacy target.Type = DatabaseTypeHelper.ConvertFromDisplayName(typeName); } else { // Current target.Type = DatabaseTypeHelper.ConvertDatabaseTypeNameToDatabaseType(typeName); } if (rootIsEmpty && target.Type is StringType) { target.ValueString = null; } else { target.ValueString = valueString ?? ""; } }
/// <summary> /// Add a formatted message representing a change in a field. /// </summary> /// <param name="field"></param> /// <param name="oldValue"></param> /// <param name="newValue"></param> public void AddChangedField(Field field, object oldValue, object newValue) { if (oldValue == null && newValue == null) { throw new ArgumentException(); } var change = new ChangeRecord { Field = field.Name }; _changes.Add(change); var fieldRnType = field.GetFieldType().ReadiNowType; var dbType = DatabaseTypeHelper.ConvertDatabaseTypeNameToDatabaseType(field.GetFieldType().ReadiNowType); Func <object, string> converter = (o) => FormatField(dbType.ConvertToString(o)); if (oldValue == null) { change.UpdateType = "set"; } else if (newValue == null) { change.UpdateType = "cleared"; } else { change.UpdateType = "changed"; } var sb = new StringBuilder(); switch (field.GetFieldType().ReadiNowType) { case "BoolType": change.UpdateType = "changed"; // Booleans get special handling due to false and null being the same AddTo(sb, converter, newValue ?? (object)false); // special handling for nulls with bools. break; case "CurrencyType": case "DecimalType": case "Int32Type": case "DateType": case "TimeType": case "GuidType": AddFromTo(sb, converter, oldValue, newValue); break; case "DateTimeType": AddFromTo(sb, ZuluDateTimeConverter, oldValue, newValue); break; case "StringType": if (!SkipSummary(field)) { AddFromTo(sb, converter, oldValue, newValue); } break; case "BinaryType": case "IdentifierType": case "DocumentType": case "XmlType": case "AutoIncrementType": // do nothing - values are not displayable. default: break; } change.Summary = sb.ToString(); }