private static void SerializeStructure(EdiWriter writer, Stack <EdiStructure> stack, EdiPathComparer structuralComparer = null) { structuralComparer = structuralComparer ?? new EdiPathComparer(writer.Grammar); var structure = stack.Peek(); var properies = structure.GetOrderedProperties(structuralComparer); foreach (var property in properies) { var value = property.Info.GetValue(structure.Instance); if (property.ValueInfo != null) { var path = (EdiPath)writer.Path; var propertyPath = property.PathInfo.PathInternal; var container = stack.Skip(1).FirstOrDefault(); if (propertyPath.Segment.IsWildcard) { if (container.Descriptor.Path.HasValue && !container.Descriptor.Path.Value.Segment.IsWildcard) { propertyPath = new EdiPath(container.Descriptor.Path.Value.Segment, propertyPath.Element, propertyPath.Component); } } if (propertyPath.Element.IsWildcard) { propertyPath = new EdiPath(propertyPath.Segment, new EdiPathFragment(structure.Index.ToString()), propertyPath.Component); } if (path.Segment != propertyPath.Segment || structuralComparer.Compare(path, propertyPath) > 0) { writer.WriteSegmentName(propertyPath.Segment); path = (EdiPath)writer.Path; } // the following loop handles the write of unmapped preceding elements/components to the one being writen // so that path progression stays intact even though we do not have all properties present on the model. while (structuralComparer.Compare(path, propertyPath) < 0) { if (!path.Element.Equals(propertyPath.Element)) { if (path.ElementIndex == 0 && writer.WriteState != WriteState.Component && writer.WriteState != WriteState.Element) { writer.WriteToken(EdiToken.Null); } else { writer.WriteToken(EdiToken.ElementStart); } } else if (!path.Component.Equals(propertyPath.Component)) { if (path.ComponentIndex == 0 && writer.WriteState != WriteState.Component) { writer.WriteToken(EdiToken.Null); } else { writer.WriteToken(EdiToken.ComponentStart); } } path = (EdiPath)writer.Path; } // handle auto generated values. if (property.AutoGenerationInfo != null) { // do stuff. // there should be plenty of things to work with inside the EdiWriter itself. // We are already keeping keeping track of current position with an index. // But it may need to track more stuff in order for this to happen. } writer.WriteValue(value, property.ValueInfo.Picture, property.ValueInfo.Format); } else { // this is somekind of structure. Group/Message/Segment/SegmentGroup/Element // is it a collection of some kind? var container = property.Attributes.InferStructure(); if (property.Info.PropertyType.IsCollectionType()) { var itemType = default(Type); var collection = (value ?? new object[0]) as IList; if (property.Info.PropertyType.IsArray) { itemType = property.Info.PropertyType.GetElementType(); } else { itemType = property.Info.PropertyType.GetGenericArguments().First(); } for (var i = 0; i < collection.Count; i++) { var item = collection[i]; if (stack.Count == 0) { throw new EdiException($"Serialization stack empty while in the middle of proccessing a collection of {itemType.Name}"); } while (stack.Peek().StructureType >= container) { var previous = stack.Pop(); } stack.Push(new EdiStructure(container, stack.Peek(), property, item, i, null)); SerializeStructure(writer, stack, structuralComparer); } } else { // or a simple Container. if (stack.Count == 0) { throw new EdiException($"Serialization stack empty while in the middle of proccessing a collection of {property.Info.PropertyType.Name}"); } while (stack.Peek().StructureType >= container) { var previous = stack.Pop(); } if (value == null) { continue; } stack.Push(new EdiStructure(container, stack.Peek(), property, value)); SerializeStructure(writer, stack, structuralComparer); } } } }
/// <summary> /// Serializes the structure. /// </summary> /// <param name="writer">Writer.</param> /// <param name="stack">Stack.</param> /// <param name="structuralComparer">Structural comparer.</param> private static void SerializeStructure(EdiWriter writer, Stack <EdiStructure> stack, EdiPathComparer structuralComparer = null) { structuralComparer = structuralComparer ?? new EdiPathComparer(writer.Grammar); var structure = stack.Peek(); var properies = structure.GetOrderedProperties(structuralComparer); foreach (var property in properies) { var value = property.Info.GetValue(structure.Instance); if (property.ValueInfo != null) { var path = (EdiPath)writer.Path; if (path.Segment != property.PathInfo.Segment || structuralComparer.Compare(path, property.PathInfo.PathInternal) > 0) { writer.WriteSegmentName(property.PathInfo.Segment); } while (structuralComparer.Compare(path, property.PathInfo.PathInternal) < 0) { path = (EdiPath)writer.Path; if (path.ElementIndex != property.PathInfo.ElementIndex) { writer.WriteToken(EdiToken.ElementStart); } else if (path.ComponentIndex != property.PathInfo.ComponentIndex) { writer.WriteToken(EdiToken.ComponentStart); } } writer.WriteValue(value, property.ValueInfo.Picture, property.ValueInfo.Format); } else { // this is somekind of structure. Group/Message/Segment/SegmentGroup/Element // is it a collection of some kind? var container = property.Attributes.InferStructure(); if (property.Info.PropertyType.IsCollectionType()) { var itemType = default(Type); var collection = (value ?? new object[0]) as IList; if (property.Info.PropertyType.IsArray) { itemType = property.Info.PropertyType.GetElementType(); } else { itemType = property.Info.PropertyType.GetGenericArguments().First(); } for (var i = 0; i < collection.Count; i++) { var item = collection[i]; if (stack.Count == 0) { throw new EdiException($"Serialization stack empty while in the middle of proccessing a collection of {itemType.Name}"); } while (stack.Peek().Container >= container) { var previous = stack.Pop(); } stack.Push(new EdiStructure(container, item, i, null)); SerializeStructure(writer, stack, structuralComparer); } } else { // or a simple Container. if (stack.Count == 0) { throw new EdiException($"Serialization stack empty while in the middle of proccessing a collection of {property.Info.PropertyType.Name}"); } while (stack.Peek().Container >= container) { var previous = stack.Pop(); } if (value == null) { continue; } stack.Push(new EdiStructure(container, value)); SerializeStructure(writer, stack, structuralComparer); } } } }
internal void PopulateValue(EdiReader reader, Stack <EdiStructure> stack, ref EdiPathComparer structuralComparer) { structuralComparer = new EdiPathComparer(reader.Grammar); var current = stack.Peek(); var maxLevelsUp = 0; var level = 0; // stack always enumerates backwards so this is a search upwards :-) // we search only if we need to have more than one property populated with the value from the reader. // maxLevelsUp = zero means only the current level (quicker). foreach (var structure in stack) { if (level++ > maxLevelsUp) { break; } var typeDescriptor = structure.Descriptor; var valueProps = typeDescriptor.Properties .Where(p => p.ValueInfo != null && p.Path != null && (((EdiPath)p.Path).Equals(reader.Path) || structure.CachedReads.ContainsPath(p.Path)) ).OrderBy(p => (EdiPath)p.Path, structuralComparer).ToArray(); for (var i = 0; i < valueProps.Length; i++) { var descriptor = valueProps[i]; // should I use the text reader? // Values must be read only once on first pass! // Otherwise the reader position moves forward // and the serializer gets out of sync. var useTheReader = current == structure && reader.TokenType == EdiToken.ComponentStart && ((EdiPath)descriptor.Path).Equals(reader.Path) && i == 0; switch (ConvertUtils.GetTypeCode(descriptor.Info.PropertyType)) { case PrimitiveTypeCode.Empty: break; case PrimitiveTypeCode.Object: PopulateObjectValue(reader, structure, descriptor, useTheReader); break; case PrimitiveTypeCode.Char: case PrimitiveTypeCode.CharNullable: PopulateCharValue(reader, structure, descriptor, useTheReader); break; case PrimitiveTypeCode.Boolean: case PrimitiveTypeCode.BooleanNullable: PopulateBooleanValue(reader, structure, descriptor, useTheReader); break; case PrimitiveTypeCode.SByte: break; case PrimitiveTypeCode.SByteNullable: break; case PrimitiveTypeCode.Int16: break; case PrimitiveTypeCode.Int16Nullable: break; case PrimitiveTypeCode.UInt16: break; case PrimitiveTypeCode.UInt16Nullable: break; case PrimitiveTypeCode.Int32: case PrimitiveTypeCode.Int32Nullable: PopulateInt32Value(reader, structure, descriptor, useTheReader); break; case PrimitiveTypeCode.Byte: break; case PrimitiveTypeCode.ByteNullable: break; case PrimitiveTypeCode.UInt32: break; case PrimitiveTypeCode.UInt32Nullable: break; case PrimitiveTypeCode.Int64: break; case PrimitiveTypeCode.Int64Nullable: break; case PrimitiveTypeCode.UInt64: break; case PrimitiveTypeCode.UInt64Nullable: break; case PrimitiveTypeCode.Single: case PrimitiveTypeCode.SingleNullable: case PrimitiveTypeCode.Double: case PrimitiveTypeCode.DoubleNullable: case PrimitiveTypeCode.Decimal: case PrimitiveTypeCode.DecimalNullable: PopulateDecimalValue(reader, structure, descriptor, useTheReader); break; case PrimitiveTypeCode.DateTime: case PrimitiveTypeCode.DateTimeNullable: PopulateDateTimeValue(reader, structure, descriptor, useTheReader); break; case PrimitiveTypeCode.DateTimeOffset: break; case PrimitiveTypeCode.DateTimeOffsetNullable: break; case PrimitiveTypeCode.Guid: break; case PrimitiveTypeCode.GuidNullable: break; case PrimitiveTypeCode.TimeSpan: break; case PrimitiveTypeCode.TimeSpanNullable: break; case PrimitiveTypeCode.BigInteger: break; case PrimitiveTypeCode.BigIntegerNullable: break; case PrimitiveTypeCode.Uri: break; case PrimitiveTypeCode.String: PopulateStringValue(reader, structure, descriptor, useTheReader); break; case PrimitiveTypeCode.Bytes: break; case PrimitiveTypeCode.DBNull: break; } } } }
private static void SerializeStructure(EdiWriter writer, Stack <EdiStructure> stack, EdiPathComparer structuralComparer = null) { structuralComparer = structuralComparer ?? new EdiPathComparer(writer.Grammar); var structure = stack.Peek(); var properies = structure.GetOrderedProperties(structuralComparer); foreach (var property in properies) { var value = property.Info.GetValue(structure.Instance); if (property.ValueInfo != null) { var path = (EdiPath)writer.Path; if (path.Segment != property.PathInfo.Segment || structuralComparer.Compare(path, property.PathInfo.PathInternal) > 0) { writer.WriteSegmentName(property.PathInfo.Segment); path = (EdiPath)writer.Path; } // the following loop handles the write of unmapped preceding elements/components to the one being writen // so that path progression stays intact even though we do not have all properties present on the model. // TODO: Potentialy this is related to compression. while (structuralComparer.Compare(path, property.PathInfo.PathInternal) < 0) { path = (EdiPath)writer.Path; if (path.ElementIndex == 0 && writer.WriteState != WriteState.Component && writer.WriteState != WriteState.Element) { writer.WriteToken(EdiToken.Null); } else if (path.ElementIndex != property.PathInfo.ElementIndex) { writer.WriteToken(EdiToken.ElementStart); } else if (path.ComponentIndex == 0 && writer.WriteState != WriteState.Component && writer.WriteState != WriteState.Element) { writer.WriteToken(EdiToken.Null); } else if (path.ComponentIndex != property.PathInfo.ComponentIndex) { writer.WriteToken(EdiToken.ComponentStart); } } writer.WriteValue(value, property.ValueInfo.Picture, property.ValueInfo.Format); } else { // this is somekind of structure. Group/Message/Segment/SegmentGroup/Element // is it a collection of some kind? var container = property.Attributes.InferStructure(); if (property.Info.PropertyType.IsCollectionType()) { var itemType = default(Type); var collection = (value ?? new object[0]) as IList; if (property.Info.PropertyType.IsArray) { itemType = property.Info.PropertyType.GetElementType(); } else { itemType = property.Info.PropertyType.GetGenericArguments().First(); } for (var i = 0; i < collection.Count; i++) { var item = collection[i]; if (stack.Count == 0) { throw new EdiException($"Serialization stack empty while in the middle of proccessing a collection of {itemType.Name}"); } while (stack.Peek().StructureType >= container) { var previous = stack.Pop(); } stack.Push(new EdiStructure(container, stack.Peek(), property, item, i, null)); SerializeStructure(writer, stack, structuralComparer); } } else { // or a simple Container. if (stack.Count == 0) { throw new EdiException($"Serialization stack empty while in the middle of proccessing a collection of {property.Info.PropertyType.Name}"); } while (stack.Peek().StructureType >= container) { var previous = stack.Pop(); } if (value == null) { continue; } stack.Push(new EdiStructure(container, stack.Peek(), property, value)); SerializeStructure(writer, stack, structuralComparer); } } } }