/// <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) { // notice that Linq.Union enumerates first and second in that order and yields each element that has not // already been yielded; see https://msdn.microsoft.com/en-us/library/bb341731 IEnumerable <PropertyExtractor> mergedExtractors; var schemaExtractors = Extractors; switch (pipelineExtractors.Precedence) { case ExtractorPrecedence.Schema: mergedExtractors = schemaExtractors.Union(pipelineExtractors, _lambdaComparer); break; case ExtractorPrecedence.SchemaOnly: mergedExtractors = schemaExtractors.Any() ? schemaExtractors : pipelineExtractors; break; case ExtractorPrecedence.Pipeline: mergedExtractors = pipelineExtractors.Union(schemaExtractors, _lambdaComparer); break; case ExtractorPrecedence.PipelineOnly: mergedExtractors = pipelineExtractors.Any() ? pipelineExtractors : schemaExtractors; break; default: throw new InvalidOperationException(string.Format("Unknown ExtractorPrecedence value '{0}'.", pipelineExtractors.Precedence)); } // filter out extractors to be ignored return(mergedExtractors.Where(pe => pe.ExtractionMode != ExtractionMode.Ignore).ToArray()); }
public void UnionWithSchemaPrecedenceOfSchemaAndPipelineExtractorsHavingSchemaPropertyExtractorsToBeIgnored() { var schemaExtractors = new PropertyExtractorCollection( new PropertyExtractor(new XmlQualifiedName("prop1", "urn"), ExtractionMode.Ignore), new PropertyExtractor(new XmlQualifiedName("prop2", "urn"), ExtractionMode.Ignore), new ConstantExtractor(new XmlQualifiedName("cso-prop", "urn"), "constant", ExtractionMode.Write), new XPathExtractor(new XmlQualifiedName("xso-prop", "urn"), "*/other-node", ExtractionMode.Write), new ConstantExtractor(new XmlQualifiedName("c-prop", "urn"), "constant", ExtractionMode.Write), new XPathExtractor(new XmlQualifiedName("x-prop", "urn"), "*/other-node", ExtractionMode.Write)); var pipelineExtractors = new PropertyExtractorCollection( ExtractorPrecedence.Schema, new PropertyExtractor(new XmlQualifiedName("prop1", "urn"), ExtractionMode.Clear), new PropertyExtractor(new XmlQualifiedName("prop2", "urn"), ExtractionMode.Clear), new ConstantExtractor(new XmlQualifiedName("cpo-prop", "urn"), "constant", ExtractionMode.Promote), new XPathExtractor(new XmlQualifiedName("xpo-prop", "urn"), "*/other-node", ExtractionMode.Promote), new ConstantExtractor(new XmlQualifiedName("c-prop", "urn"), "constant", ExtractionMode.Promote), new XPathExtractor(new XmlQualifiedName("x-prop", "urn"), "*/other-node", ExtractionMode.Promote)); var expectedExtractors = schemaExtractors .Where(pe => pe.ExtractionMode != ExtractionMode.Ignore) .Concat( new PropertyExtractor[] { new ConstantExtractor(new XmlQualifiedName("cpo-prop", "urn"), "constant", ExtractionMode.Promote), new XPathExtractor(new XmlQualifiedName("xpo-prop", "urn"), "*/other-node", ExtractionMode.Promote) }); Assert.That(schemaExtractors.Union(pipelineExtractors), Is.EqualTo(expectedExtractors)); }
public void UnionWithSchemaPrecedenceOfSchemaAndEmptyPipelineExtractors() { var schemaExtractors = new PropertyExtractorCollection( new ConstantExtractor(new XmlQualifiedName("cso-prop", "urn"), "constant", ExtractionMode.Write), new XPathExtractor(new XmlQualifiedName("xso-prop", "urn"), "*/other-node", ExtractionMode.Write), new ConstantExtractor(new XmlQualifiedName("c-prop", "urn"), "constant", ExtractionMode.Write), new XPathExtractor(new XmlQualifiedName("x-prop", "urn"), "*/other-node", ExtractionMode.Write)); var pipelineExtractors = new PropertyExtractorCollection(ExtractorPrecedence.Schema); Assert.That(schemaExtractors.Union(pipelineExtractors), Is.EqualTo(schemaExtractors)); }
public void UnionWithPipelinePrecedenceOfSchemaAndPipelineExtractors() { var schemaExtractors = new PropertyExtractorCollection( new ConstantExtractor(new XmlQualifiedName("cso-prop", "urn"), "constant", ExtractionMode.Write), new XPathExtractor(new XmlQualifiedName("xso-prop", "urn"), "*/other-node", ExtractionMode.Write), new ConstantExtractor(new XmlQualifiedName("c-prop", "urn"), "constant", ExtractionMode.Write), new XPathExtractor(new XmlQualifiedName("x-prop", "urn"), "*/other-node", ExtractionMode.Write)); var pipelineExtractors = new PropertyExtractorCollection( ExtractorPrecedence.Pipeline, new ConstantExtractor(new XmlQualifiedName("cpo-prop", "urn"), "constant", ExtractionMode.Promote), new XPathExtractor(new XmlQualifiedName("xpo-prop", "urn"), "*/other-node", ExtractionMode.Promote), new ConstantExtractor(new XmlQualifiedName("c-prop", "urn"), "constant", ExtractionMode.Promote), new XPathExtractor(new XmlQualifiedName("x-prop", "urn"), "*/other-node", ExtractionMode.Promote)); var expectedExtractors = pipelineExtractors.Concat( new PropertyExtractor[] { new ConstantExtractor(new XmlQualifiedName("cso-prop", "urn"), "constant", ExtractionMode.Write), new XPathExtractor(new XmlQualifiedName("xso-prop", "urn"), "*/other-node", ExtractionMode.Write) }); Assert.That(schemaExtractors.Union(pipelineExtractors), Is.EqualTo(expectedExtractors)); }