/// <summary> /// Check an XmlElement to see if it includes a specific "Type" attribute. If so, return /// the actual Type associated with that attribute's value. /// </summary> /// <param name="_xml">The XmlElement containing the field's information</param> /// <param name="_defaultType"> /// If there is no Type attribute, then return this value as the "default" /// </param> /// <returns> /// NULL if no Type attribute was found, or the Type object corresponding the value of /// the Type attribute /// </returns> /// <exception cref="InvalidOperationException"> /// Thrown if there is a Type attribute, but that attribute's value cannot be turned /// into a Type object. /// </exception> private Type GetTypeFromXmlOrDefault(XmlElement _xml, Type _defaultType) { var sType = XmlExtensions.GetAttributeValue(_xml, m_context.TypeAttributeName); if (sType == null) // There is no explicit Type specifier (XmlAttribute) { return(_defaultType); } var explicitType = Lib.BetterGetType(sType, true); if (explicitType == null) { // The XML had an explicit Type, but that Type couldn't be found. So... If we // are trying to deserialize a Type that uses EntitySemantics, we assume that // the destination Type is sufficient to figure out what to deserialize. If the // destination Type is wholly inadequate to "receive" the data in the XML, the // application is at fault. For Entities, this type of mismatch is OK. if (CEntityTypeData.UsesEntitySemantics(_defaultType)) { return(_defaultType); } // However, if this isn't using EntitySemantics, then throw an exception as the // Type is unknown. throw new XDeserializationError("An Attribute was found for an Explicit Type, but it could not be turned into a Type: " + sType); } return(explicitType); }
/// <summary> /// Using childNodes from an element, deserialize an array by deserializing the /// individual elements into the array elements. /// </summary> /// <param name="_xml"> /// The XML parent node containing the array elements as childNodes /// </param> /// <param name="_arrayHelper">The ArrayDeserializationHelper</param> private void DeserializeArrayFromElements(XmlElement _xml, CArrayDeserializationHelper _arrayHelper) { foreach (XmlNode node in _xml.ChildNodes) { if (!(node is XmlElement elem)) { throw new XDeserializationError(node.NodeType.ToString() + " was the nodetype found (instead of XmlElement) as a child of the array's XML"); } int[] indicies = null; var sIndex = XmlExtensions.GetAttributeValue(elem, m_context.ArrayIndexAttributeName); if (sIndex != null) { indicies = sIndex.Split(',').Select(s => int.Parse(s)).ToArray(); } if (indicies != null && indicies.Length > 0) { _arrayHelper.SetIndicies(indicies); } var obj = FrameworkDeserialize(elem, _arrayHelper.ElementType); _arrayHelper.Add(obj); } }
/// <summary> /// Check the easiest forms of deserialization- Null and RefTo an object already /// deserialized. /// </summary> /// <param name="_xml">The XML that's being deserialized</param> /// <param name="_workObj"> /// The Object that was deserialized (when the return value is TRUE) /// </param> /// <returns> /// TRUE means that the _workObj parameter contains valid data and nothing further /// should be done, FALSE means that no deserialization was performed. /// </returns> private bool CheckNullAndReference(XmlElement _xml, CWorkingObject _workObj) { // Check the XML to see if this is a NULL object reference. If it is, then return // TRUE. if (XmlExtensions.HasAttribute(_xml, m_context.NullAttributeName)) { return(true); } // Check the XML to see if its referring to some other object. var referTo = XmlExtensions.GetAttributeValue(_xml, m_context.ReferToAttributeName); if (referTo != null) // There was a reference to another object, so handle it and return that other object. { // Check the table for the RefID to get the object. The reference must be in the // table already because forward-looking references are not supported. if (!m_references.TryGetValue(referTo, out var obj)) { throw new XUnknownReference("All object-references must be to backward-defined objects. The RefID " + referTo + " has not been defined yet."); } _workObj.Set(obj); return(true); } // Check to see if this element is associating the XML with a reference ID var refId = XmlExtensions.GetAttributeValue(_xml, m_context.ReferenceIdAttributeName); if (refId != null) { _workObj.SetRefInfo(this, refId); } return(false); }
/// <summary> /// Given information about the current state, create an ArrayDeserializationHelper to /// help with the deserialization process /// </summary> /// <param name="_xml">The XML containing the Array information</param> /// <param name="_type">The Type of the array expected</param> /// <param name="_workingObject"> /// A "Working Object", likely from a surrogate that didn't complete the deserialization /// </param> /// <param name="_inferredLength"> /// The Inferred Length of the array, from a "Condensed Array" already found in the XML /// </param> /// <returns> /// A properly formed <see cref="CArrayDeserializationHelper"/> object. /// </returns> private CArrayDeserializationHelper CreateArrayDeserializationHelper(XmlElement _xml, Type _type, CWorkingObject _workingObject, int _inferredLength) { CArrayDeserializationHelper arrayHelper; if (_workingObject.IsSet) { arrayHelper = new CArrayDeserializationHelper(_workingObject.WorkingObject as Array); } else { // Make sure that the array type actually is an array and it has an ElementType var arrType = _type; if (!arrType.IsArray) { throw new XDeserializationError( "The Type specified is not an array or it does not have an ElementTypes associated with it- " + arrType.ToString()); } // Get info from the XML var sLengths = XmlExtensions.GetAttributeValue(_xml, m_context.ArrayAttributeName); var lengths = sLengths?.Split(',').Select(s => int.Parse(s)).ToArray(); var sLowerBounds = XmlExtensions.GetAttributeValue(_xml, m_context.ArrayLowerBoundAttribute); var lowerBounds = sLowerBounds?.Split(',').Select(s => int.Parse(s)).ToArray(); if (lengths == null) { if (_inferredLength > -1) { lengths = new int[] { _inferredLength } } ; else { lengths = new int[] { InferArrayLength(_xml) } }; // This assumes a 1-dim array at this point. } arrayHelper = new CArrayDeserializationHelper(arrType.GetElementType(), lengths, lowerBounds); } return(arrayHelper); }
/// <summary> /// This routine will try to figure out how large an array is based on the nodes in the /// XML /// </summary> /// <param name="_xml"></param> /// <returns></returns> private int InferArrayLength(XmlElement _xml) { // XmlNode node = _xml.SelectSingleNode( @"*/*[@idx][last()]" ); var index = 0; foreach (XmlNode node in _xml.ChildNodes) { var sIndex = XmlExtensions.GetAttributeValue(node, m_context.ArrayIndexAttributeName); if (!string.IsNullOrEmpty(sIndex)) { index = int.Parse(sIndex); } index++; } return(index); }
/// <summary> /// Check to see if the object has been serialized before. If it has, then make sure /// that the reference information for it is added. /// </summary> /// <remarks>This routine has the overloaded</remarks> /// <param name="_object">The object that's being serialized</param> /// <param name="_elementForObject"> /// The element that the object is being serialized to /// </param> /// <returns>TRUE if the object is a duplicate, FALSE if it is a "new" object</returns> private bool HandleDuplicateReferences(object _object, XmlElement _elementForObject) { var oType = _object.GetType(); if (oType.IsPrimitive) { return(false); } if (oType == TYPEOF_STRING && !m_context.DuplicateStringsCanBeReferredTo) { return(false); } if (oType.IsEnum) { return(false); } if (m_references.TryGetValue(_object, out var refElem)) // The object was serialized already { if (ReferenceEquals(_elementForObject, refElem)) // If this IS the referenced element, then skip it { return(false); } var refId = XmlExtensions.GetAttributeValue(refElem, m_context.ReferenceIdAttributeName); if (refId == null) // The object that was serialized doesn't have its RefID set yet { refId = m_refId.ToString(); XmlExtensions.AddAttribute(refElem, m_context.ReferenceIdAttributeName, refId); m_refId++; } // Add the "ReferTo" attribute to the xml XmlExtensions.AddAttribute(_elementForObject, m_context.ReferToAttributeName, refId); // Remove a "Type" attribute (if it exists) because this becomes redundant with // the presence of RefTo XmlExtensions.RemoveAttribute(_elementForObject, m_context.TypeAttributeName); return(true); } m_references.Add(_object, _elementForObject); return(false); }