public static string Serialize(PropertyExtractorCollection extractors) { if (extractors == null || !extractors.Any()) { return(null); } using (var stringWriter = new StringWriter()) using (var writer = XmlWriter.Create(stringWriter, new XmlWriterSettings { OmitXmlDeclaration = true })) { extractors.WriteXml(writer); writer.Flush(); return(stringWriter.ToString()); } }
/// <summary> /// Merges two sets of <see cref="PropertyExtractor"/>-derived extractors by honoring their <see cref="Precedence"/> and assuming that this <see /// cref="PropertyExtractorCollection"/> instance contains the <see cref="PropertyExtractor"/>s configured by XML schema annotations and that <see /// cref="PropertyExtractorCollection"/> being merged into contains the <see cref="PropertyExtractor"/>s configured by the pipeline. /// </summary> /// <param name="pipelineExtractors"> /// The <see cref="PropertyExtractor"/>s configured by the pipeline. /// </param> /// <returns> /// The result of the merge between two sets of <see cref="PropertyExtractor"/>-derived extractors. /// </returns> /// <remarks> /// <para> /// The merge algorithm proceeds as follows: /// <list type="bullet"> /// <item> /// The <see cref="Precedence"/> of the <see cref="PropertyExtractor"/>s configured by XML schema annotations is irrelevant and discarded, no matter /// what its value may be. In other words, only the <see cref="Precedence"/> of the <see cref="PropertyExtractor"/>s configured by the pipeline is /// actually relevant. If unspecified, the <see cref="Precedence"/> of the <see cref="PropertyExtractor"/>s configured by the pipeline will be assumed /// to be given to the <see cref="ExtractorPrecedence.Schema"/>. /// </item> /// <item> /// If the <see cref="Precedence"/> of the pipeline <see cref="PropertyExtractor"/>s is given to the <see cref="ExtractorPrecedence.Schema"/> then any /// <see cref="PropertyExtractor"/> <b>redefined</b> by the pipeline will be ignored. In other words, for these particular <see /// cref="PropertyExtractor"/>s <b>redefined</b> by the pipeline, only their configuration done by the schema annotations will be retained. The <see /// cref="PropertyExtractor"/>s defined either only by the annotations or only by the pipeline will of course be part of the resulting merge. /// </item> /// <item> /// If the <see cref="Precedence"/> of the pipeline <see cref="PropertyExtractor"/>s is set to <see cref="ExtractorPrecedence.SchemaOnly"/> then any /// <see cref="PropertyExtractor"/> defined by the pipeline will be ignored provided that there are <see cref="PropertyExtractor"/>s configured by XML /// schema annotations. In other words, if there are <see cref="PropertyExtractor"/>s configured by annotations then the merge operation will return /// only these and discard any <see cref="PropertyExtractor"/>s configured by the pipeline. But if there are no <see cref="PropertyExtractor"/>s /// configured by annotations then the merge operation will return only the <see cref="PropertyExtractor"/>s configured by the the pipeline. /// </item> /// <item> /// If the <see cref="Precedence"/> of the pipeline <see cref="PropertyExtractor"/>s is given to the <see cref="ExtractorPrecedence.Pipeline"/> then /// any <see cref="PropertyExtractor"/> <b>redefined</b> by the pipeline will have precedence over the one defined by the annotations. In other words, /// for these particular <see cref="PropertyExtractor"/>s <b>redefined</b> by the pipeline, only their configuration done by the pipeline will be /// retained. The <see cref="PropertyExtractor"/>s defined either only by the annotations or only by the pipeline will of course be part of the /// resulting merge. /// </item> /// <item> /// If the <see cref="Precedence"/> of the pipeline <see cref="PropertyExtractor"/>s is set to <see cref="ExtractorPrecedence.PipelineOnly"/> then any /// <see cref="PropertyExtractor"/> defined by XML schema annotations will be ignored provided that there are <see cref="PropertyExtractor"/>s /// configured by the pipeline. In other words, if there are <see cref="PropertyExtractor"/>s configured by the pipeline then the merge operation will /// return only these and discard any <see cref="PropertyExtractor"/>s configured by annotations. But if there are no <see cref="PropertyExtractor"/>s /// configured by the pipeline then the merge operation will return only the <see cref="PropertyExtractor"/>s configured by annotations. /// </item> /// <item> /// Notice that <see cref="PropertyExtractor"/>s whose <see cref="PropertyExtractor.ExtractionMode"/> is set to <see cref="ExtractionMode.Ignore"/> /// will be filtered out of the resulting set of <see cref="PropertyExtractor"/>s only after the merge operation have proceeded. This could therefore /// lead to interesting results if the <see cref="Precedence"/> of the pipeline's <see cref="PropertyExtractor"/>s is either set to <see /// cref="ExtractorPrecedence.Pipeline"/> or <see cref="ExtractorPrecedence.Schema"/>. /// </item> /// </list> /// </para> /// </remarks> public IEnumerable <PropertyExtractor> Union(PropertyExtractorCollection pipelineExtractors) { if (pipelineExtractors == null) { throw new ArgumentNullException(nameof(pipelineExtractors)); } // notice that Linq.Union enumerates first and second in that order and yields each element that has not // already been yielded; see https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.union var schemaExtractors = Extractors; var mergedExtractors = pipelineExtractors.Precedence switch { ExtractorPrecedence.Schema => schemaExtractors.Union(pipelineExtractors, _lambdaComparer), ExtractorPrecedence.SchemaOnly => schemaExtractors.Any() ? schemaExtractors : pipelineExtractors, ExtractorPrecedence.Pipeline => pipelineExtractors.Union(schemaExtractors, _lambdaComparer), ExtractorPrecedence.PipelineOnly => pipelineExtractors.Any() ? pipelineExtractors : schemaExtractors, _ => throw new InvalidOperationException($"Unknown ExtractorPrecedence value '{pipelineExtractors.Precedence}'.") }; // filter out extractors to be ignored return(mergedExtractors.Where(pe => pe.ExtractionMode != ExtractionMode.Ignore).ToArray()); }