/// <summary> /// Adds an <see cref="string"/> XML converter to the list. /// </summary> /// <param name="converters">The list of XML converters.</param> public static void AddStringConverter(this IList <XmlConverter> converters) { converters.AddXmlConverter <string>((w, s, q) => { if (s.IsNullOrWhiteSpace()) { return; } if (w.WriteState == WriteState.Start && q == null) { q = new XmlQualifiedEntity(typeof(string).ToFriendlyName()); } w.WriteEncapsulatingElementIfNotNull(s, q, (writer, value) => { if (value.IsXmlString()) { writer.WriteCData(value); } else { writer.WriteValue(value); } }); }); }
public override void WriteXml(XmlWriter writer, object value, XmlQualifiedEntity elementName = null) { if (Writer == null) { throw new NotImplementedException("Delegate writer is null."); } Writer.Invoke(writer, value, elementName ?? RootName); }
internal DynamicXmlConverterCore(Type objectType, Action <XmlWriter, object, XmlQualifiedEntity> writer, Func <XmlReader, Type, object> reader, Func <Type, bool> secondaryCanConvertPredicate, XmlQualifiedEntity rootName) { RootName = rootName; ObjectType = objectType; Writer = writer; Reader = reader; CanConvertPredicate = secondaryCanConvertPredicate; }
/// <summary> /// Creates and returns a chunked sequence of <see cref="XmlReader"/> objects with a maximum of the specified <paramref name="size"/> of XML node elements located on a depth of 1. /// </summary> /// <param name="reader">The <see cref="XmlReader"/> object that contains the XML data to chunk into smaller <see cref="XmlReader"/> objects for a batch run or similar.</param> /// <param name="size">The amount of XML node elements allowed per <see cref="XmlReader"/> object. Default is 128 XML node element.</param> /// <param name="setup">The <see cref="XmlWriterSettings"/> which need to be configured.</param> /// <returns>An sequence of <see cref="XmlReader"/> objects that contains no more than the specified <paramref name="size"/> of XML node elements from the <paramref name="reader" /> object.</returns> /// <exception cref="System.ArgumentNullException"> /// <paramref name="reader"/> is null. /// </exception> /// <exception cref="System.ArgumentException"> /// The <see cref="XmlReader.Read"/> method of the <paramref name="reader"/> object has already been called. /// </exception> public static IEnumerable <XmlReader> Chunk(XmlReader reader, int size, Action <XmlWriterSettings> setup = null) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (reader.ReadState != ReadState.Initial) { throw new ArgumentException("The Read method of the XmlReader object has already been called.", nameof(reader)); } List <XmlReader> outerReaders = new List <XmlReader>(); XmlReaderSettings readerSettings = reader.Settings; if (MoveToFirstElement(reader)) { XmlQualifiedEntity rootElement = new XmlQualifiedEntity(reader.Prefix, reader.LocalName, reader.NamespaceURI); List <XmlReader> innerReaders = new List <XmlReader>(); Stream result; while (reader.Read()) { if (reader.Depth > 1) { continue; } switch (reader.NodeType) { case XmlNodeType.Element: XPathDocument document = new XPathDocument(reader.ReadSubtree()); XPathNavigator navigator = document.CreateNavigator(); innerReaders.Add(navigator.ReadSubtree()); break; } if (innerReaders.Count != size) { continue; } result = XmlWriterUtility.CreateXml(ChunkCore, innerReaders, rootElement, setup); outerReaders.Add(XmlReader.Create(result, readerSettings)); innerReaders.Clear(); } if (innerReaders.Count > 0) { result = XmlWriterUtility.CreateXml(ChunkCore, innerReaders, rootElement, setup); outerReaders.Add(XmlReader.Create(result, readerSettings)); innerReaders.Clear(); } } return(outerReaders); }
internal static XmlQualifiedEntity LookupXmlStartElement(this IHierarchy <object> node, XmlQualifiedEntity qualifiedRootEntity = null) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (qualifiedRootEntity != null && !qualifiedRootEntity.LocalName.IsNullOrWhiteSpace()) { return(qualifiedRootEntity); } bool hasRootAttribute = TypeUtility.ContainsAttributeType(node.InstanceType, true, typeof(XmlRootAttribute)); bool hasElementAttribute = node.HasMemberReference && TypeUtility.ContainsAttributeType(node.MemberReference, typeof(XmlElementAttribute)); string rootOrElementName = XmlUtility.SanitizeElementName(node.HasMemberReference ? node.MemberReference.Name : StringConverter.FromType(node.InstanceType, false, true)); string ns = null; if (hasRootAttribute || hasElementAttribute) { string elementName = null; if (hasRootAttribute) { XmlRootAttribute rootAttribute = node.InstanceType.GetTypeInfo().GetCustomAttribute <XmlRootAttribute>(true); elementName = rootAttribute.ElementName; ns = rootAttribute.Namespace; } if (hasElementAttribute) { XmlElementAttribute elementAttribute = node.MemberReference.GetCustomAttribute <XmlElementAttribute>(); elementName = elementAttribute.ElementName; ns = elementAttribute.Namespace; } if (!string.IsNullOrEmpty(elementName)) { rootOrElementName = elementName; } } XmlQualifiedEntity instance = node.Instance as XmlQualifiedEntity; return(instance ?? new XmlQualifiedEntity(XmlUtility.SanitizeElementName(rootOrElementName), ns)); }
private void WriteXmlChildren(XmlWriter writer, IHierarchy <object> node) { foreach (IHierarchy <object> childNode in node.GetChildren().OrderByXmlAttributes()) { if (childNode.HasXmlIgnoreAttribute()) { return; } XmlQualifiedEntity qualifiedEntity = childNode.LookupXmlStartElement(); if (childNode.HasChildren && TypeUtility.IsComplex(childNode.InstanceType)) { writer.WriteStartElement(qualifiedEntity.Prefix, qualifiedEntity.LocalName, qualifiedEntity.Namespace); } WriteXmlNodes(writer, childNode); if (childNode.HasChildren && TypeUtility.IsComplex(childNode.InstanceType)) { writer.WriteEndElement(); } } }
private void WriteXmlChildren(XmlWriter writer, IHierarchy <object> node) { foreach (IHierarchy <object> childNode in node.GetChildren().OrderByXmlAttributes()) { if (childNode.HasXmlIgnoreAttribute()) { continue; } if (!childNode.InstanceType.GetTypeInfo().IsValueType&& childNode.Instance == null) { continue; } if (childNode.InstanceType.IsEnumerable() && childNode.InstanceType != typeof(string) && !childNode.InstanceType.IsDictionary()) { var i = childNode.Instance as IEnumerable; if (i == null || i.Cast <object>().Count() == 0) { continue; } } XmlQualifiedEntity qualifiedEntity = childNode.LookupXmlStartElement(); if (childNode.HasChildren && TypeUtility.IsComplex(childNode.InstanceType)) { writer.WriteStartElement(qualifiedEntity); } var converter = Converters.FirstOrDefaultWriterConverter(childNode.InstanceType); if (converter != null) { converter.WriteXml(writer, childNode.Instance, qualifiedEntity); } else { WriteXmlNodes(writer, childNode); } if (childNode.HasChildren && TypeUtility.IsComplex(childNode.InstanceType)) { writer.WriteEndElement(); } } }
/// <summary> /// Initializes a new instance of the <see cref="DefaultXmlConverter"/> class. /// </summary> public DefaultXmlConverter(XmlQualifiedEntity rootName, IList <XmlConverter> converters) { RootName = rootName; Converters = converters ?? new List <XmlConverter>(); }
private static void ChunkCore(XmlWriter writer, IEnumerable <XmlReader> readers, XmlQualifiedEntity rootElement) { if (readers == null) { throw new ArgumentNullException(nameof(readers)); } if (writer == null) { throw new ArgumentNullException(nameof(writer)); } writer.WriteStartElement(rootElement.Prefix, rootElement.LocalName, rootElement.Namespace); foreach (XmlReader reader in readers) { try { writer.WriteNode(reader, true); } finally { reader.Dispose(); } } writer.WriteEndDocument(); }
private static void WriteXmlRootElementCore(XmlWriter writer, object value, Action <XmlWriter, object> treeWriterPublic, Action <XmlWriter, IHierarchy <object> > treeWriterInternal, XmlQualifiedEntity rootEntity = null) { Validator.ThrowIfNull(writer, nameof(writer)); Validator.ThrowIfNull(value, nameof(value)); try { IHierarchy <object> nodes; XmlQualifiedEntity rootElement; if (treeWriterInternal == null) { nodes = new Hierarchy <object>().Add(value); rootElement = nodes.LookupXmlStartElement(rootEntity); writer.WriteStartElement(rootElement.Prefix, rootElement.LocalName, rootElement.Namespace); treeWriterPublic?.Invoke(writer, value); } else { nodes = new HierarchySerializer(value).Nodes; rootElement = nodes.LookupXmlStartElement(rootEntity); writer.WriteStartElement(rootElement.Prefix, rootElement.LocalName, rootElement.Namespace); treeWriterInternal(writer, nodes); } } catch (Exception ex) { Exception innerException = ex; if (innerException is OutOfMemoryException) { throw; } if (innerException is TargetInvocationException) { innerException = innerException.InnerException; } throw ExceptionUtility.Refine(new InvalidOperationException("There is an error in the XML document.", innerException), MethodBaseConverter.FromType(typeof(XmlWriterExtensions), flags: ReflectionUtility.BindingInstancePublicAndPrivateNoneInheritedIncludeStatic), writer, value).Unwrap(); } writer.WriteEndElement(); writer.Flush(); }
/// <summary> /// Creates a dynamic instance of an <see cref="XmlConverter" /> implementation wrapping <see cref="XmlConverter.WriteXml" /> through <paramref name="writer" /> and <see cref="XmlConverter.ReadXml" /> through <paramref name="reader" />. /// </summary> /// <typeparam name="T">The type to implement an <see cref="XmlConverter" />.</typeparam> /// <param name="writer">The delegate that converts <typeparamref name="T" /> to its XML representation.</param> /// <param name="reader">The delegate that generates <typeparamref name="T" /> from its XML representation.</param> /// <param name="canConvertPredicate">The predicate that determines if an <see cref="XmlConverter"/> can convert.</param> /// <param name="rootEntity">The optional <seealso cref="XmlQualifiedEntity"/> that will provide the name of the root element.</param> /// <returns>An <see cref="XmlConverter" /> implementation of <typeparamref name="T" />.</returns> public static XmlConverter Create <T>(Action <XmlWriter, T, XmlQualifiedEntity> writer = null, Func <XmlReader, Type, T> reader = null, Func <Type, bool> canConvertPredicate = null, XmlQualifiedEntity rootEntity = null) { var castedWriter = writer == null ? (Action <XmlWriter, object, XmlQualifiedEntity>)null : (w, t, q) => writer(w, (T)t, q); var castedReader = reader == null ? (Func <XmlReader, Type, object>)null : (r, t) => reader(r, t); return(Create(typeof(T), castedWriter, castedReader, canConvertPredicate, rootEntity)); }
/// <summary> /// Writes the specified <paramref name="value"/> with the delegate <paramref name="nodeWriter"/>. /// If <paramref name="elementName"/> is not null, then the delegate <paramref name="nodeWriter"/> is called from within an encapsulating Start- and End-element. /// </summary> /// <typeparam name="T">The type of the object to serialize.</typeparam> /// <param name="writer">The writer used in the serialization process.</param> /// <param name="value">The object to serialize.</param> /// <param name="elementName">The optional fully qualified name of the element.</param> /// <param name="nodeWriter">The delegate node writer.</param> public static void WriteEncapsulatingElementIfNotNull <T>(this XmlWriter writer, T value, XmlQualifiedEntity elementName, Action <XmlWriter, T> nodeWriter) { if (elementName == null) { nodeWriter(writer, value); return; } writer.WriteStartElement(elementName); nodeWriter(writer, value); writer.WriteEndElement(); }
/// <summary> /// Writes the specified start tag and associates it with the given <paramref name="elementName"/>. /// </summary> /// <param name="writer">The writer used in the serialization process.</param> /// <param name="elementName">The fully qualified name of the element.</param> public static void WriteStartElement(this XmlWriter writer, XmlQualifiedEntity elementName) { writer.WriteStartElement(elementName.Prefix, elementName.LocalName, elementName.Namespace); }
private void WriteXmlEnumerable(XmlWriter writer, IHierarchy <object> current, bool skipStartElement = false) { Type currentType = current.InstanceType; Type[] genericParameters = currentType.GetGenericArguments(); if (genericParameters.Length == 0) { genericParameters = null; } if (TypeUtility.IsEnumerable(currentType) && currentType != typeof(string)) { bool isDictionary = TypeUtility.IsDictionary(currentType); IEnumerable enumerable = current.Instance as IEnumerable; if (enumerable != null) { var list = enumerable.Cast <object>().ToList(); if (!skipStartElement && !current.HasChildren && list.Count > 0) { XmlQualifiedEntity qualifiedEntity = null; if (!current.InstanceType.HasAttributes(typeof(XmlRootAttribute)) && current.MemberReference == null) { qualifiedEntity = new XmlQualifiedEntity(StringConverter.FromType(current.InstanceType, false, true).SanitizeElementName()); } qualifiedEntity = current.LookupXmlStartElement(qualifiedEntity); writer.WriteStartElement(qualifiedEntity.Prefix, qualifiedEntity.LocalName, qualifiedEntity.Namespace); } IEnumerator enumerator = list.GetEnumerator(); IHierarchy <object> enumeratorNode = new Hierarchy <object>(); enumeratorNode.Add(enumerator); while (enumerator.MoveNext()) { object value = enumerator.Current; if (value == null) { continue; } writer.WriteStartElement(EnumerableElementName); Type valueType = value.GetType(); if (isDictionary) { PropertyInfo keyProperty = valueType.GetProperty("Key"); PropertyInfo valueProperty = valueType.GetProperty("Value"); object keyValue = keyProperty.GetValue(value, null) ?? "null"; object valueValue = valueProperty.GetValue(value, null) ?? "null"; var kvpWrapper = DynamicXmlSerializable.Create(new[] { keyValue, valueValue }, (xmlWriter, o) => { var k = o[0]; var v = ReflectionUtility.GetObjectHierarchy(o[1], options => options.MaxDepth = 0); v.Data.Add("enumerableCaller", true); writer.WriteAttributeString("key", k.ToString()); XmlQualifiedEntity qualifiedEntity = null; if (genericParameters != null && genericParameters.Length > 0) { qualifiedEntity = new XmlQualifiedEntity(StringConverter.FromType(genericParameters.Last(), false, true).SanitizeElementName()); } qualifiedEntity = v.LookupXmlStartElement(qualifiedEntity); writer.WriteStartElement(qualifiedEntity.Prefix, qualifiedEntity.LocalName, qualifiedEntity.Namespace); WriteXmlNodes(writer, v); writer.WriteEndElement(); }); WriteXmlNodes(writer, ReflectionUtility.GetObjectHierarchy(kvpWrapper, options => options.MaxDepth = 0)); } else { IHierarchy <object> itemNode = ReflectionUtility.GetObjectHierarchy(value, options => options.MaxDepth = 0); itemNode.Data.Add("enumerableCaller", true); XmlQualifiedEntity qualifiedEntity = null; if (genericParameters != null && genericParameters.Length > 0) { qualifiedEntity = new XmlQualifiedEntity(StringConverter.ToDelimitedString(genericParameters, "And", StringConverter.FromType)); } qualifiedEntity = itemNode.LookupXmlStartElement(qualifiedEntity); writer.WriteStartElement(qualifiedEntity.Prefix, qualifiedEntity.LocalName, qualifiedEntity.Namespace); WriteXmlNodes(writer, itemNode); writer.WriteEndElement(); } writer.WriteEndElement(); } if (!skipStartElement && !current.HasChildren && list.Count > 0) { writer.WriteEndElement(); } } } }
/// <summary> /// Creates a dynamic instance of an <see cref="XmlConverter" /> implementation wrapping <see cref="XmlConverter.WriteXml" /> through <paramref name="writer" /> and <see cref="XmlConverter.ReadXml" /> through <paramref name="reader" />. /// </summary> /// <param name="objectType">The type of the object to make convertible.</param> /// <param name="writer">The delegate that converts an object to its XML representation.</param> /// <param name="reader">The delegate that generates an object from its XML representation.</param> /// <param name="canConvertPredicate">The predicate that determines if an <see cref="XmlConverter" /> can convert.</param> /// <param name="rootEntity">The optional <seealso cref="XmlQualifiedEntity"/> that will provide the name of the root element.</param> /// <returns>An <see cref="XmlConverter" /> implementation of an object.</returns> public static XmlConverter Create(Type objectType, Action <XmlWriter, object, XmlQualifiedEntity> writer = null, Func <XmlReader, Type, object> reader = null, Func <Type, bool> canConvertPredicate = null, XmlQualifiedEntity rootEntity = null) { return(new DynamicXmlConverterCore(objectType, writer, reader, canConvertPredicate, rootEntity)); }
/// <summary> /// Writes the XML root element to an existing <paramref name="writer"/>. /// </summary> /// <typeparam name="T">The type of the object to serialize.</typeparam> /// <param name="writer">The writer used in the serialization process.</param> /// <param name="value">The object to serialize.</param> /// <param name="treeWriter">The delegate used to write the XML hierarchy.</param> /// <param name="rootEntity">The optional <seealso cref="XmlQualifiedEntity"/> that will provide the name of the root element.</param> public static void WriteXmlRootElement <T>(this XmlWriter writer, T value, Action <XmlWriter, T, XmlQualifiedEntity> treeWriter, XmlQualifiedEntity rootEntity = null) { WriteXmlRootElementCore(writer, value, (w, o) => treeWriter(w, value, rootEntity), null, rootEntity); }
/// <summary> /// Converts an object into its XML representation. /// </summary> /// <param name="writer">The <see cref="XmlWriter" /> stream to which the object is serialized.</param> /// <param name="value">The object to convert.</param> /// <param name="elementName">The element name to encapsulate around <paramref name="value" />.</param> /// <exception cref="InvalidOperationException">There is an error in the XML document.</exception> public override void WriteXml(XmlWriter writer, object value, XmlQualifiedEntity elementName = null) { writer.WriteXmlRootElement(value, WriteXmlNodes, elementName ?? RootName); }
internal static void WriteXmlRootElement(this XmlWriter writer, object value, Action <XmlWriter, IHierarchy <object> > treeWriter, XmlQualifiedEntity rootEntity = null) { WriteXmlRootElementCore(writer, value, null, treeWriter, rootEntity); }
/// <summary> /// Inserts an XML converter to the list at the specified <paramref name="index" />. /// </summary> /// <typeparam name="T">The type of the object to converts to and from XML.</typeparam> /// <param name="converters">The list of XML converters.</param> /// <param name="index">The zero-based index at which an XML converter should be inserted.</param> /// <param name="writer">The delegate that converts <typeparamref name="T" /> to its XML representation.</param> /// <param name="reader">The delegate that generates <typeparamref name="T" /> from its XML representation.</param> /// <param name="canConvertPredicate">The delegate that determines if an object can be converted.</param> /// <param name="qe">The optional <seealso cref="XmlQualifiedEntity"/> that will provide the name of the root element.</param> public static void InsertXmlConverter <T>(this IList <XmlConverter> converters, int index, Action <XmlWriter, T, XmlQualifiedEntity> writer = null, Func <XmlReader, Type, T> reader = null, Func <Type, bool> canConvertPredicate = null, XmlQualifiedEntity qe = null) { converters.Insert(index, DynamicXmlConverter.Create(writer, reader, canConvertPredicate, qe)); }
/// <summary> /// Writes the XML representation of the <paramref name="value" />. /// </summary> /// <param name="writer">The <see cref="XmlWriter" /> to write to.</param> /// <param name="value">The object to serialize.</param> /// <param name="elementName">The element name to encapsulate around <paramref name="value"/>.</param> public abstract void WriteXml(XmlWriter writer, object value, XmlQualifiedEntity elementName = null);