private void WriteProperty(string propName, Type propType, object propVal, XmlWriter output, int[] pos, EntityAttributeAttribute attr, bool wrap = false) { //don't write anything if this is uninitialized optional item set var optSet = propVal as IOptionalItemSet; if (optSet != null && !optSet.Initialized) { return; } //null or a value type that maybe null, need to write out sets and lists if they are mandatroy but empty if (propVal == null) { if (!typeof(IExpressEnumerable).GetTypeInfo().IsAssignableFrom(propType) || attr.State != EntityAttributeState.Mandatory) { return; } //write out empty mandatory set with proper enumeration type output.WriteStartElement(propName); //output.WriteAttributeString("cType", attr.ListType); output.WriteEndElement(); return; } if (propType.GetTypeInfo().IsInterface&& typeof(IExpressSelectType).GetTypeInfo().IsAssignableFrom(propType)) // a select type get the type of the actual value { var realType = propVal.GetType(); var exprType = _metadata.ExpressType(realType); var realName = exprType != null ? exprType.ExpressName : realType.Name; output.WriteStartElement(propName); WriteProperty(realName, realType, propVal, output, null, attr, true); output.WriteEndElement(); return; } //make sure we don't mess around with nullables propType = XmlMetaProperty.GetNonNullableType(propType); if (typeof(IExpressValueType).GetTypeInfo().IsAssignableFrom(propType)) { var cpl = propVal as IExpressComplexType; if (cpl != null) { var expT = _metadata.ExpressType(propVal.GetType()); if (expT != null && expT.UnderlyingType != null && typeof(IEnumerable <IPersistEntity>).GetTypeInfo().IsAssignableFrom(expT.UnderlyingType)) { output.WriteStartElement(expT.ExpressName + (wrap ? "-wrapper" : "")); var idx = new[] { 0 }; foreach (var ent in cpl.Properties.Cast <IPersistEntity>()) { WriteEntity(ent, output, false, idx); idx[0]++; } output.WriteEndElement(); return; } } var valString = cpl == null ? propVal.ToString() : string.Join(" ", cpl.Properties); output.WriteStartElement(propName + (wrap ? "-wrapper" : "")); if (pos != null) { output.WriteAttributeString("pos", string.Join(" ", pos)); } output.WriteValue(valString); output.WriteEndElement(); return; } if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(propType) && propType != typeof(string)) { //special case for IfcRelDefinesByProperties //if (propName == "RelatedObjects" && entity.ExpressType.Name == "IfcRelDefinesByProperties") if (attr.MaxCardinality != null && attr.MaxCardinality.Length == 1 && attr.MaxCardinality[0] == 1) //list which shouldn't have more than 1 element in is serialized as a single element { propVal = ((IEnumerable)propVal).Cast <object>().FirstOrDefault(); var relEntity = propVal as IPersistEntity; if (relEntity == null) { return; } WriteEntity(relEntity, output, false, null, propName); return; } var propValEnum = ((IEnumerable)propVal).Cast <object>().ToList(); //inverse attribute with no values if (attr.Order < 0 && !propValEnum.Any()) { return; } var idx = new List <int>(pos ?? new int[] {}) { 0 }; var depth = idx.Count - 1; if (depth == 0) { output.WriteStartElement(propName); //output.WriteAttributeString(_nsPrefix, "cType", _ns, attr.ListType); } foreach (var item in propValEnum) { var expT = _metadata.ExpressType(item.GetType()); var name = expT != null ? expT.ExpressName : item.GetType().Name; WriteProperty(name, item.GetType(), item, output, idx.ToArray(), attr, true); idx[depth]++; } if (depth == 0) { output.WriteEndElement(); } return; } if (typeof(IPersistEntity).GetTypeInfo().IsAssignableFrom(propType)) { var persistEntity = (IPersistEntity)propVal; WriteEntity(persistEntity, output, false, pos, propName); return; } //this will only be called from within the enumeration //as otherwise it will be serialized as XML attribute before if (propType.GetTypeInfo().IsValueType || typeof(string) == propType || typeof(byte[]) == propType) { var pInfoType = propVal.GetType(); string pValue; if (pInfoType.GetTypeInfo().IsEnum) //convert enum { output.WriteStartElement(propName); pValue = propVal.ToString().ToLower(); } else if (pInfoType.GetTypeInfo().UnderlyingSystemType == typeof(Boolean)) { output.WriteStartElement("boolean-wrapper"); pValue = (bool)propVal ? "true" : "false"; } else if (pInfoType.GetTypeInfo().UnderlyingSystemType == typeof(Double) || pInfoType.GetTypeInfo().UnderlyingSystemType == typeof(Single)) { output.WriteStartElement("double-wrapper"); pValue = string.Format(new Part21Formatter(), "{0:R}", propVal); } else if (pInfoType.GetTypeInfo().UnderlyingSystemType == typeof(Int16)) { output.WriteStartElement("integer-wrapper"); pValue = propVal.ToString(); } else if (pInfoType.GetTypeInfo().UnderlyingSystemType == typeof(Int32) || pInfoType.GetTypeInfo().UnderlyingSystemType == typeof(Int64)) { output.WriteStartElement("long-wrapper"); pValue = propVal.ToString(); } else if (pInfoType.GetTypeInfo().UnderlyingSystemType == typeof(String)) //convert string { output.WriteStartElement("string-wrapper"); pValue = string.Format(new Part21Formatter(), "{0}", propVal); } else if (pInfoType.GetTypeInfo().UnderlyingSystemType == typeof(byte[])) { output.WriteStartElement("hexBinary-wrapper"); var ba = (byte[])propVal; var hex = new System.Text.StringBuilder(ba.Length * 2); foreach (byte b in ba) { hex.AppendFormat("{0:X2}", b); } pValue = hex.ToString(); } else { throw new NotSupportedException(string.Format("Invalid Value Type {0}", pInfoType.Name)); } output.WriteAttributeString("pos", string.Join(" ", pos)); output.WriteValue(pValue); output.WriteEndElement(); return; } #if DEBUG throw new Exception("Unexpected type"); #endif }