internal static ElementStrategy AddKeyedElementType(MergeStrategies mergeStrategies, string name, string attribute, bool orderOfTheseIsRelevant)
 {
     var strategy = new ElementStrategy(orderOfTheseIsRelevant)
                     {
                         MergePartnerFinder = new FindByKeyAttribute(attribute)
                     };
     mergeStrategies.SetStrategy(name, strategy);
     return strategy;
 }
		private static ElementStrategy MakeClassStrategy(FieldWorkObjectContextGenerator descriptor, MergeStrategies strategies)
		{
			var classStrat = new ElementStrategy(false)
			{
				MergePartnerFinder = GuidKey,
				ContextDescriptorGenerator = descriptor,
				IsAtomic = false
			};
			descriptor.MergeStrategies = strategies;
			return classStrat;
		}
		internal static void AddElementStrategies(MergeStrategies mergeStrategies)
		{
			// Document root.
			mergeStrategies.SetStrategy("LayoutInventory", ElementStrategy.CreateSingletonElement());

			#region 'layoutType' and children.
			mergeStrategies.SetStrategy("layoutType", ElementStrategy.CreateSingletonElement());

			var elStrat = new ElementStrategy(false)
				{
					MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> { "class", "layout" }),
					NumberOfChildren = NumberOfChildrenAllowed.Zero,
					IsAtomic = true,
					ContextDescriptorGenerator = new FieldWorkCustomLayoutContextGenerator()
				};
			mergeStrategies.SetStrategy("configure", elStrat);
			#endregion 'layoutType' and children.

			#region 'layout' and children.
			elStrat = new ElementStrategy(false)
				{
					MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> { "class", "type", "name" }),
					ContextDescriptorGenerator = new FieldWorkCustomLayoutContextGenerator()
				};
			mergeStrategies.SetStrategy("layout", elStrat);

			elStrat = new ElementStrategy(true)
				{
					MergePartnerFinder = new FindByKeyAttributeInList("ref"),
					IsAtomic = true
				};
			mergeStrategies.SetStrategy("part", elStrat);

			elStrat = new ElementStrategy(true)
				{
					//MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> { "class", "fieldType", "restrictions" }),
					MergePartnerFinder = new FindByKeyAttributeInList("combinedkey"),
					IsAtomic = true
				};
			mergeStrategies.SetStrategy("generate", elStrat);

			elStrat = new ElementStrategy(true)
				{
					MergePartnerFinder = new FindByKeyAttributeInList("name"),
					IsAtomic = true,
					NumberOfChildren = NumberOfChildrenAllowed.Zero
				};
			mergeStrategies.SetStrategy("sublayout", elStrat);
			#endregion 'layout' and children.
		}
        /// <summary>
        /// Add all of the Lift range related ElementStrategy instances suitable for use in the lift file, and the lift-ranges file.
        /// </summary>
        /// <remarks>
        /// NB: There are more element strategies needed to support ranges, but they are expected to be defined elsewhere, as they are common to other non-range elements.
        /// Examples: "description" and "form" elements.
        /// </remarks>
        internal static void AddLiftRangeElementStrategies(MergeStrategies mergeStrategies)
        {
            // ******************************* <lift-ranges> **************************************************
            // The root element of the Lift Ranges file type.
            // <lift-ranges
            //		<range> [Required, Multiple, range]
            // </lift-ranges>
            // ******************************* </lift-ranges> **************************************************

            // ******************************* <range> **************************************************
            // <range
            //		id [Required, key]
            var elementStrategy = LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "range", "id", false);
            elementStrategy.ContextDescriptorGenerator = new LiftRangeContextGenerator();
            //		guid [Optional, string]
            //		href [Optional, URL]
            elementStrategy.AttributesToIgnoreForMerging.Add("href");
            //		<description> [Optional, multitext] <description> holds zero or more <form> elements
            //		<range-element> [Optional, Multiple, range-element] RNG has <range-element>, doc and UML says <range> for a NAME OVERRIDE. Go with <range-element>, since that is what FLEx writes in the lift-ranges file.
            //		<label> [Optional, Multiple, multitext] <label> holds zero or more <form> elements
            //		<abbrev> [Optional, Multiple, multitext] <abbrev> holds zero or more <form> elements
            // </range>
            // ******************************* </range> **************************************************

            // ******************************* <ranges> **************************************************

            // ******************************* <range-element> **************************************************
            // This element appears to not be in the main lift file, so it will be 'extra', but ought not cause harm.
            // <range-element
            //		id [Required, key]
            LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "range-element", "id", false);
            //		parent [Optional, key]
            //		guid [Optional, string]
            //		<description> [Optional, multitext] <description> holds zero or more <form> elements
            //		<label> [Optional, multitext] <label> holds zero or more <form> elements
            //		<abbrev> [Optional, multitext] <abbrev> holds zero or more <form> elements
            elementStrategy = LiftBasicElementStrategiesMethod.AddSingletonElementType(mergeStrategies, "abbrev");
            elementStrategy.OrderIsRelevant = false;
            // </range-element>
            // ******************************* </range-element> **************************************************
        }
		private static FieldWorkObjectContextGenerator MakeGenerator()
		{
			var result = new FieldWorkObjectContextGenerator();
			var strategies = new MergeStrategies();
			result.MergeStrategies = strategies;
			strategies.SetStrategy("LexEntry", MakeClassStrategy(new LexEntryContextGenerator(), strategies));
			strategies.SetStrategy("ReversalIndexEntry", MakeClassStrategy(new ReversalEntryContextGenerator(), strategies));
			strategies.SetStrategy("WfiWordform", MakeClassStrategy(new WfiWordformContextGenerator(), strategies));
			strategies.SetStrategy("CmPossibilityList", MakeClassStrategy(new PossibilityListContextGenerator(), strategies));
			strategies.SetStrategy("CmPossibility", MakeClassStrategy(new PossibilityContextGenerator(), strategies));
			strategies.SetStrategy("LexEntryType", MakeClassStrategy(new PossibilityContextGenerator(), strategies));
			strategies.SetStrategy("PhEnvironment", MakeClassStrategy(new EnvironmentContextGenerator(), strategies));
			strategies.SetStrategy("DsChart", MakeClassStrategy(new DiscourseChartContextGenerator(), strategies));
			strategies.SetStrategy("DsConstChart", MakeClassStrategy(new DiscourseChartContextGenerator(), strategies));
			strategies.SetStrategy("ConstChartRow", MakeClassStrategy(new DiscourseChartContextGenerator(), strategies));
			strategies.SetStrategy("ConstChartWordGroup", MakeClassStrategy(new DiscourseChartContextGenerator(), strategies));
			strategies.SetStrategy("PhNCSegments", MakeClassStrategy(new MultiLingualStringsContextGenerator("Natural Class", "Name", "Abbreviation"), strategies));
			strategies.SetStrategy("FsClosedFeature", MakeClassStrategy(new MultiLingualStringsContextGenerator("Phonological Features", "Name", "Abbreviation"), strategies));
			strategies.SetStrategy("Text", MakeClassStrategy(new TextContextGenerator(), strategies));
			strategies.SetStrategy("RnGenericRec", MakeClassStrategy(new RnGenericRecContextGenerator(), strategies));
			strategies.SetStrategy("ScrBook", MakeClassStrategy(new ScrBookContextGenerator(), strategies));
			strategies.SetStrategy("ScrSection", MakeClassStrategy(new ScrSectionContextGenerator(), strategies));
			return result;
		}
Exemple #6
0
        public void WeDeleteNeighborsAndTheyInsertInOrder()
        {
            const string ancestor = @"<a>
                                <b key='one'>
                                    <c key='a'>first</c>
                                    <c key='b'>second</c>
                                    <c key='c'>third</c>
                                    <c key='d'>fourth</c>
                               </b>
                            </a>";

            const string ours = @"<a>
                                <b key='one'>
                                    <c key='a'>first</c>
                                    <c key='d'>fourth</c>
                               </b>
                            </a>";

            const string theirs = @"<a>
                                <b key='one'>
                                    <c key='a'>first</c>
                                    <c key='b'>second</c>
                                    <c key='z'>extra</c>
                                    <c key='c'>third</c>
                                    <c key='d'>fourth</c>
                               </b>
                            </a>";

            MergeStrategies _mergeStrategies = new MergeStrategies(); ;
            _mergeStrategies.ElementStrategies.Add("a", ElementStrategy.CreateSingletonElement());
            _mergeStrategies.ElementStrategies.Add("b", ElementStrategy.CreateForKeyedElementInList("key"));
            _mergeStrategies.ElementStrategies.Add("c", ElementStrategy.CreateForKeyedElementInList("key"));
            XmlTestHelper.DoMerge(
                _mergeStrategies,
                ancestor, ours, theirs,
                new List<string> {
                    "a/b[@key='one']/c[1][@key='a' and text()='first']",
                    "a/b[@key='one']/c[2][@key='z' and text()='extra']",
                    "a/b[@key='one']/c[3][@key='d' and text()='fourth']" },
                new List<string> { "a/b[@key='one']/c[@key='b']", "a/b[@key='one']/c[@key='c']" },
                0, null,
                3, new List<Type> { typeof(XmlTextDeletedReport), typeof(XmlTextDeletedReport), typeof(XmlTextAddedReport) });
        }
 private static void AddVariantStrategy(MergeStrategies mergeStrategies)
 {
     var strategy = new ElementStrategy(false)
                     {
                         MergePartnerFinder = new OptionalKeyAttrFinder("ref", new FormMatchingFinder())
                     };
     strategy.AttributesToIgnoreForMerging.Add("dateModified");
     mergeStrategies.SetStrategy("variant", strategy);
 }
 private static void AddTranslationStrategy(MergeStrategies mergeStrategies)
 {
     var strategy = new ElementStrategy(false)
                     {
                         MergePartnerFinder = new OptionalKeyAttrFinder("type", new FormMatchingFinder())
                     };
     mergeStrategies.SetStrategy("translation", strategy);
 }
 /* Called <pronunciation> in lift file.
 private static void AddPhoneticStrategy(MergeStrategies mergeStrategies)
 {
     var strategy = new ElementStrategy(false)
                     {
                         MergePartnerFinder = new FormMatchingFinder()
                     };
     strategy.AttributesToIgnoreForMerging.Add("dateModified");
     mergeStrategies.SetStrategy("phonetic", strategy);
 }*/
 private static void AddPronunciationStrategy(MergeStrategies mergeStrategies)
 {
     var strategy = new ElementStrategy(false)
                     {
                         MergePartnerFinder = new FormMatchingFinder()
                     };
     strategy.AttributesToIgnoreForMerging.Add("dateModified");
     mergeStrategies.SetStrategy("pronunciation", strategy);
 }
        internal static void AddLiftElementStrategies(MergeStrategies mergeStrategies)
        {
            LiftBasicElementStrategiesMethod.AddLiftBasicElementStrategies(mergeStrategies);
            LiftRangesElementStrategiesMethod.AddLiftRangeElementStrategies(mergeStrategies);

            #region Header Elements

            //enhance: don't currently have a way of limiting etymology/form to a single instance but not multitext/form

            // ******************************* <lift> **************************************************
            // Added to complete the whole file, but it gets no ElementStrategy.
            // <lift
            //		version [Required, (string?)]
            //		producer [Optional, string]
            //		<header> [Optional, header]
            //		<entry> [Optional, Multiple, Entry]
            // </lift>
            // ******************************* <lift> **************************************************

            // ******************************* <header> **************************************************
            // <header
            var elementStrategy = AddSingletonElementType(mergeStrategies, "header");
            elementStrategy.ContextDescriptorGenerator = new LiftHeaderContextGenerator();
            //		<description> [Optional, multitext] NAME OVERRIDE (Declared in [LiftBasicElementStrategiesMethod], as it is shared here and in the lift-ranges file.)
            //		<ranges> [Optional, ranges]
            elementStrategy = AddSingletonElementType(mergeStrategies, "ranges");
            elementStrategy.OrderIsRelevant = false;
            //		<fields> [Optional, field-defns] NAME OVERRIDE
            elementStrategy = AddSingletonElementType(mergeStrategies, "fields");
            elementStrategy.OrderIsRelevant = false;
            // </header>
            // ******************************* </header> **************************************************

            // ******************************* <ranges> **************************************************
            // <ranges
            //		<range> [Optional, Multiple, range-ref] NAME OVERRIDE
            //	NB: Done in LiftRangesElementStrategiesMethod
            // </ranges>
            // ******************************* </ranges> **************************************************

            // ******************************* <field-defns> **************************************************
            // <field-defns
            //		<field> [Optional, Multiple, field-defn] NAME OVERRIDE
            // </field-defns>
            // ******************************* </field-defns> **************************************************

            // ******************************* <field-defn> **************************************************
            // <field-defn> element never occurs in the wild (0.13), as it always gets a name change to <field>.
            // <field-defn (aka <field> in 0.13)
            //		tag [Required, key]
            // !!!!!!!!! HACK ALERT !!!!!!!!!
            LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "headerfield", "tag", false);
            // !!!!!!!!! END HACK ALERT !!!!!!!!!
            //		<form> [optional, multiple]
            // </field-defn>
            // ******************************* </field-defn> **************************************************

            #endregion #region Header Elements

            #region Entry Elements

            // ******************************* <extensible> **************************************************
            // Notes: This is only be a bundle of attrs and content others can use, rather than an actual element in the file.
            // <extensible
            //		dateCreated [Optional, datetime] // attr in UML
            //		dateModified [Optional, datetime] // attr in UML
            //		<field> [Optional, Multiple, field]
            //		<trait> [Optional, Multiple, trait] // NB: sig changed in text to 'flag', but 'trait' in UML.
            //		<annotation> [Optional, Multiple, annotation]
            // </extensible>
            // It is 'abstract', so no element strategy is needed.
            // ******************************* </extensible> **************************************************

            // ******************************* <field> **************************************************
            // Technically part of Base, but I don't know why, as the <field> elements appear in entries (or maybe senses).
            // Formal inheritance from <multitext>, and partial from <extensible> (all but <field>).
            // Observation: <field> inherits everything, except its 'type' attribute.
            // <field
            //		type [Required, sig=key]
            // !!!!!!!!! HACK ALERT !!!!!!!!!
            elementStrategy = LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "mainfield", "type", false);
            // !!!!!!!!! END HACK ALERT !!!!!!!!!
            //		dateCreated [Optional, sig=datetime, inherited from <extensible>]
            //		dateModified [Optional, sig=datetime, inherited from <extensible>]
            elementStrategy.AttributesToIgnoreForMerging.Add("dateModified");
            //		<trait> [Optional, Multiple, trait, inherited from <extensible>]
            //		<annotation> [Optional, Multiple, sig=annotation, inherited from <extensible>]
            //		<form> [Optional, Multiple, sig=form, inherited from <multitext>]
            // </field>
            // ******************************* </field> **************************************************

            // ******************************* <trait> **************************************************
            // Notes: A trait is simply a reference to a single range-element
            //		in a range. It can be used to give the dialect for a variant or the status of an entry.
            //		The semantics of a trait in a particular context is given by the parent object and also by the range
            //		and range-element being referred to. Where no range is linked the name is informal or resolved by name.
            // <trait
            //		name [Required, sig=key]
            //		value [Required, sig=key]
            elementStrategy = new ElementStrategy(false)
                                {
                                    // Need both keys to find the match.
                                    MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> { "name", "value" })
                                };
            mergeStrategies.SetStrategy("trait", elementStrategy);
            //		id [Optional, sig=key] // Note: Gives the particular trait an identifier such that it can be referenced by a sibling element.
            //									The id key only needs to be unique within the parent element, although globale keys may be used.
            //									There is no requirement that the key keeps its value across different versions of the file.
            //		<annotation /> [Optional, Multiple, sig=annotation]
            // </trait>
            // ******************************* </trait> **************************************************

            // ******************************* <note> **************************************************
            // <note
            //		type [Optional, sig=key] There is only one note with a given type in any parent element.
            //									Thus translations of the note are held as different forms of the one note.
            elementStrategy = new ElementStrategy(false)
                                {
                                    MergePartnerFinder = new OptionalKeyAttrFinder("type", new FormMatchingFinder())
                                };
            //		dateCreated [Optional, sig=datetime, inherited from <extensible>]
            //		dateModified [Optional, sig=datetime, inherited from <extensible>]
            elementStrategy.AttributesToIgnoreForMerging.Add("dateModified");
            //		<field> [Optional, Multiple, sig=field, inherited from <extensible>]
            //		<trait> [Optional, Multiple, sig=trait, inherited from <extensible>]
            //		<annotation> [Optional, Multiple, sig=annotation, inherited from <extensible>]
            //		<form> [Optional, Multiple, sig=form, inherited from <multitext>]
            mergeStrategies.SetStrategy("note", elementStrategy);
            // </note>
            // ******************************* </note> **************************************************

            // ******************************* <relation> **************************************************
            // <relation
            //		type [Required, sig=key]
            //		ref [Required, sig=refid]
            elementStrategy = new ElementStrategy(false)
                                {
                                    // Need both keys to find this puppy's match.
                                    MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> { "type", "ref" })
                                };
            mergeStrategies.SetStrategy("relation", elementStrategy);
            //		order [Optional, sig=int]
            //		dateCreated [Optional, sig=datetime, inherited from <extensible>]
            //		dateModified [Optional, sig=datetime, inherited from <extensible>]
            elementStrategy.AttributesToIgnoreForMerging.Add("dateModified");
            //		<field> [Optional, Multiple, sig=field, inherited from <extensible>]
            //		<trait> [Optional, Multiple, sig=trait, inherited from <extensible>]
            //		<annotation> [Optional, Multiple, sig=annotation, inherited from <extensible>]
            //		<usage> [Optional, sig=multitext]
            AddSingletonElementType(mergeStrategies, "usage");
            // </relation>
            // ******************************* </relation> **************************************************

            #region Entry

            // ******************************* <entry> **************************************************
            // <entry
            //		id [Optional, refid] This gives a unique identifier to this Entry. Notice that this is unique across all Entrys and **all Senses**.
            elementStrategy = LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "entry", "id", false);
            elementStrategy.ContextDescriptorGenerator = new LexEntryContextGenerator();
            //		order [Optional, int]
            //		guid [Optional, string]
            //		dateDeleted [Optional, datetime]
            elementStrategy.AttributesToIgnoreForMerging.Add("dateDeleted"); // One might think it is immutable, but it might not be true.
            //		dateCreated [Optional, sig=datetime, inherited from <extensible>]
            //		dateModified [Optional, sig=datetime, inherited from <extensible>]
            elementStrategy.AttributesToIgnoreForMerging.Add("dateModified");
            //		<field> [Optional, Multiple, sig=field, inherited from <extensible>]
            //		<trait> [Optional, Multiple, sig=trait, inherited from <extensible>]
            //		<annotation> [Optional, Multiple, sig=annotation, inherited from <extensible>]
            //		<lexical-unit> [Optional, multitext]
            AddSingletonElementType(mergeStrategies, "lexical-unit");
            //		<citation> [Optional, multitext]
            AddSingletonElementType(mergeStrategies, "citation");
            //		<pronunciation> [Optional, Multiple, phonetic] NAME OVERRIDE
            AddPronunciationStrategy(mergeStrategies);
            //		<variant> [Optional, Multiple, variant] dealt with below
            //		<sense> [Optional, Multiple, Sense]
            //		<note> [Optional, Multiple, note]
            //		<relation> [Optional, Multiple, relation]
            //		<etymology> [Optional, Multiple, etymology]
            // </entry>
            // ******************************* </entry> **************************************************

            // ******************************* <variant> **************************************************
            // <variant
            //		ref [Optional, refid] NOTE: Doc: refentry, UML: refid, so go with refid, since there is nothing called refentry. Gives the variation as a reference to another entry or sense rather than specifying the form
            //		dateCreated [Optional, sig=datetime, inherited from <extensible>]
            //		dateModified [Optional, sig=datetime, inherited from <extensible>]
            //		<field> [Optional, Multiple, sig=field, inherited from <extensible>]
            //		<trait> [Optional, Multiple, sig=trait, inherited from <extensible>]
            //		<annotation> [Optional, Multiple, sig=annotation, inherited from <extensible>]
            //		<form> [Optional, Multiple, sig=form, inherited from <multitext>]
            //		<pronunciation> [Optional, Multiple, sig=phonetic]
            //		<relation> [Optional, Multiple, sig=relation]
            // </variant>
            AddVariantStrategy(mergeStrategies);
            // ******************************* </variant> **************************************************

            // ******************************* <phonetic> **************************************************
            // NB: Element name changed to <pronunciation>
            // <phonetic
            //		dateCreated [Optional, sig=datetime, inherited from <extensible>]
            //		dateModified [Optional, sig=datetime, inherited from <extensible>] ignored in phonetic strategy
            //		<field> [Optional, Multiple, sig=field, inherited from <extensible>]
            //		<trait> [Optional, Multiple, sig=trait, inherited from <extensible>]
            //		<annotation> [Optional, Multiple, sig=annotation, inherited from <extensible>]
            //		<form> [Optional, Multiple, sig=form, inherited from <multitext>]
            //		<media> [Optional, Multiple, sig=URLRef] NAME OVERRIDE
            // Not ever in lift file, as <pronunciation> wraps it. AddPhoneticStrategy(mergeStrategies);
            LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "media", "href", false);
            // </phonetic>
            // ******************************* </phonetic> **************************************************

            // ******************************* <etymology> **************************************************
            // <etymology
            //		type [Required, sig=key]
            //		source [Required, sig=key] // UML has 'key', doc has 'string'. Go with key
            elementStrategy = new ElementStrategy(false)
                                {
                                    // SteveMc says to use them both.
                                    // Need both keys to find the match.
                                    MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> { "type", "source" })
                                };
            mergeStrategies.SetStrategy("etymology", elementStrategy);
            //		dateCreated [Optional, sig=datetime, inherited from <extensible>]
            //		dateModified [Optional, sig=datetime, inherited from <extensible>]
            elementStrategy.AttributesToIgnoreForMerging.Add("dateModified");
            //		<field> [Optional, Multiple, sig=field, inherited from <extensible>]
            //		<trait> [Optional, Multiple, sig=trait, inherited from <extensible>]
            //		<annotation> [Optional, Multiple, sig=annotation, inherited from <extensible>]
            //		<gloss> [Optional, Multiple, sig=form]
            //		<form> [Required, sig=form] // UML has Optional
            // </etymology>
            // ******************************* </etymology> **************************************************

            #endregion Entry

            #region Sense

            // ******************************* <sense> **************************************************
            // <sense
            //		id [Optional, refid] The id is unique across all Senses in the lexicon and all Entries as well.
            elementStrategy = LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "sense", "id", true);// main sense and nested senses, according to doc
            //		order [Optional int]
            //		dateCreated [Optional, sig=datetime, inherited from <extensible>]
            //		dateModified [Optional, sig=datetime, inherited from <extensible>]
            elementStrategy.AttributesToIgnoreForMerging.Add("dateModified");
            //		<field> [Optional, Multiple, sig=field, inherited from <extensible>]
            //		<trait> [Optional, Multiple, sig=trait, inherited from <extensible>]
            //		<annotation> [Optional, Multiple, sig=annotation, inherited from <extensible>]
            //		<grammatical-info> [Optional, grammi] grammi? Better go with grammatical-info. (Added below)
            //		<gloss> [Optional, Multiple, form]
            LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "gloss", "lang", false);
            //		<definition> [Optional, multitext]
            AddSingletonElementType(mergeStrategies, "definition");
            //		<relation> [Optional, Multiple, relation] (Added below)
            //		<note> [Optional, Multiple, note] (Added below)
            //		<example> [Optional, Multiple, example] (Must use default element strategy, or some other hand-made one.)
            //		<reversal> [Optional, Multiple, reversal] (Added below)
            //		<illustration> [Optional, Multiple, URLref] NAME OVERRIDE
            LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "illustration", "href", false);
            //		<subsense> [Optional, Multiple, sense] NAME OVERRIDE
            LiftBasicElementStrategiesMethod.AddKeyedElementType(mergeStrategies, "subsense", "id", true); // nested sense in a <sense>, according to rng
            // </sense>
            // ******************************* </sense> **************************************************

            // ******************************* <reversal> **************************************************
            // <reversal
            //		type [Optional, sig=key]
            AddReversalStrategy(mergeStrategies);
            //		<form> [Optional, Multiple, sig=form, inherited from <multitext>]
            //		<main> [Optional, sig=reversal] NAME OVERRIDE
            AddSingletonElementType(mergeStrategies, "main");
            //		<grammatical-info> [Optional, sig=grammatical-info] (Added elsewhere)
            // </reversal>
            // ******************************* </reversal> **************************************************

            // ******************************* <grammatical-info> **************************************************
            // <grammatical-info
            //		value [Required, sig=key] The part of speech tag into the grammatical-info range.
            //		<trait> {Optional, Multiple, sig=trait] Allows grammatical information to have attributes.
            // </grammatical-info>
            // Sense and reversal have this as Optional, so singleton will do, while keyed is more future-safe.
            // It may bad to use a key, since if a user changes the 'value', then we'd get two of them.
            AddSingletonElementType(mergeStrategies, "grammatical-info");
            // ******************************* </grammatical-info> **************************************************

            // ******************************* <example> **************************************************
            // <example
            AddExampleSentenceStrategy(mergeStrategies);
            // 'dateModified' is ignored in AddExampleSentenceStrategy
            //		source [Optional, key] // Not suitable for keyed el strat.
            //		dateCreated [Optional, sig=datetime, inherited from <extensible>]
            //		dateModified [Optional, sig=datetime, inherited from <extensible>]
            //		<field> [Optional, Multiple, sig=field, inherited from <extensible>]
            //		<trait> [Optional, Multiple, sig=trait, inherited from <extensible>]
            //		<annotation> [Optional, Multiple, sig=annotation, inherited from <extensible>]
            //		<form> [Optional, Multiple, sig=form, inherited from <multitext>]
            //		<translation> [Optional, Multiple, sig=translation]
            // </example>
            // ******************************* </example> **************************************************

            // ******************************* <translation> **************************************************
            // A translation is simply a multitext with an optional translation type attribute.
            // <translation
            //		type [Optional, key]
            AddTranslationStrategy(mergeStrategies);
            //		<form> [Optional, Multiple, sig=form, inherited from <multitext>]
            // </translation>
            // ******************************* </translation> **************************************************

            #endregion Sense

            #endregion End Entry Elements
        }
 public void TestTearDown()
 {
     _mergeStrategies = null;
 }
 public void TestSetup()
 {
     _mergeStrategies = new MergeStrategies();
     _mergeStrategies.ElementStrategies.Add("a", ElementStrategy.CreateSingletonElement());
     _mergeStrategies.ElementStrategies.Add("b", ElementStrategy.CreateSingletonElement());
     _mergeStrategies.ElementStrategies.Add("c", ElementStrategy.CreateSingletonElement());
     _mergeStrategies.ElementStrategies.Add("d", ElementStrategy.CreateSingletonElement());
 }
Exemple #13
0
 public XmlMerger(MergeSituation mergeSituation)
 {
     MergeSituation  = mergeSituation;
     EventListener   = new NullMergeEventListener();
     MergeStrategies = new MergeStrategies();
 }
        /// <summary>
        /// Add all of the Lift range related ElementStrategy instacnes suitable for use in the lift file, and the lift-ranges file.
        ///
        /// This will likely over-populate mergeStrategies with strategies for the lift file, but no matter.
        /// </summary>
        /// <remarks>
        /// NB: There are more element strategies needed to support ranges, but they are expected to be defined elsewhere, as they are common to other non-range elements.
        /// Examples: "description" and "form" elements.
        /// </remarks>
        internal static void AddLiftBasicElementStrategies(MergeStrategies mergeStrategies)
        {
            // ******************************* <form> **************************************************
            // <form
            //		lang='lang' (required)
            AddKeyedElementType(mergeStrategies, "form", "lang", false);
            //		<text> (Required, sig of <text>)
            //		<annotation> [Optional, Multiple, sig=annotation]
            // </form>
            // ******************************* </form> **************************************************

            // ******************************* <text> **************************************************
            // Mixes text data and <span> elements
            // 'lang' attr from parent <form> element is the defacto same thing for the <text> element, but has no attrs itself.
            // <text>
            var textStrategy = AddSingletonElementType(mergeStrategies, "text");
            textStrategy.IsAtomic = true; // don't attempt merge within text elements if they have non-text-node children, e.g., <span>
            // but we can do text-level merging if there are no spans; this allows text editing conflicts to be reported
            // and multiple text nodes which amount to the same inner text to be ignored.
            textStrategy.AllowAtomicTextMerge = true;
            // </text>
            // ******************************* </text> **************************************************

            // ******************************* <span> **************************************************
            // <span
            //		lang='lang' (optional, so how can it really be used as a key to find a match?) NB: UML chart has it as 'string', not 'lang', but 'lang' is better for us
            var elementStrategy = ElementStrategy.CreateForKeyedElementInList("lang");
            //		href='URL' (optional, ignore?)
            elementStrategy.AttributesToIgnoreForMerging.Add("href");
            //		class='string'> (optional)
            //		<span> (optional, multiple)
            // </span>
            mergeStrategies.SetStrategy("span", elementStrategy);
            // ******************************* </span> **************************************************

            // ******************************* <multitext> **************************************************
            // Formally 'inherits' from <text>, so has all it has (parent 'lang' attr governs, and other <text> rules on <span>, etc.).
            // Gotchas:
            //	1. There are no occurrences of a span being used to store content except as part of a multitext.
            //	2. text [Optional] If there is only one form the form element itself is optional and a multitext
            //		may consist of a single text node containing the contents of the text.
            //		This means that if there is no form there is no span capability.
            // <multitext		No attrs
            //		<form> [Optional, Multiple, sig=form]
            // </multitext>
            // Note: If it is 'abstract', then no element strategy is needed.
            // ******************************* </multitext> **************************************************

            // ******************************* <URLRef> **************************************************
            // <URLRef> element never occurs in the wild, as it always gets a name change.
            // <URLRef
            //		href="URL" [Required, sig=URL]
            //		<label> [Optional, sig=multitext]
            AddSingletonElementType(mergeStrategies, "label");
            // </URLRef>
            // ******************************* </URLRef> **************************************************

            // ******************************* <annotation> **************************************************
            // <annotation
            //		name [Required, key]
            //		value [Required, key]
            elementStrategy = new ElementStrategy(false)
            {
                // Need both keys to find the match.
                MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> { "name", "value" })
            };
            mergeStrategies.SetStrategy("annotation", elementStrategy);
            //		who  [Optional, key]
            //		when  [Optional, key]
            //		<form> [Optional, Multiple, sig=form, inherited from <multitext>]
            // </annotation>
            // ******************************* </annotation> **************************************************

            // Shared with <header> in lift file, <range-element> and <range> in lift and lift-ranges files.
            elementStrategy = AddSingletonElementType(mergeStrategies, "description");
            elementStrategy.OrderIsRelevant = false;
        }
Exemple #15
0
 public XmlMerger(MergeSituation mergeSituation)
 {
     MergeSituation = mergeSituation;
     EventListener  = new NullMergeEventListener();
     MergeStrategies = new MergeStrategies();
 }
Exemple #16
0
        public static string DoMerge(
			MergeStrategies mergeStrategies,
			string ancestorXml, string ourXml, string theirXml,
			IEnumerable<string> xpathQueriesThatMatchExactlyOneNode, IEnumerable<string> xpathQueriesThatReturnNull,
			int expectedConflictCount, List<Type> expectedConflictTypes,
			int expectedChangesCount, List<Type> expectedChangeTypes)
        {
            return DoMerge(
                mergeStrategies,
                new NullMergeSituation(),
                ancestorXml, ourXml, theirXml,
                xpathQueriesThatMatchExactlyOneNode, xpathQueriesThatReturnNull,
                expectedConflictCount, expectedConflictTypes,
                expectedChangesCount, expectedChangeTypes);
        }
Exemple #17
0
        public static string DoMerge(
			MergeStrategies mergeStrategies,
			MergeSituation mergeSituation,
			string ancestorXml, string ourXml, string theirXml,
			IEnumerable<string> xpathQueriesThatMatchExactlyOneNode, IEnumerable<string> xpathQueriesThatReturnNull,
			int expectedConflictCount, List<Type> expectedConflictTypes,
			int expectedChangesCount, List<Type> expectedChangeTypes)
        {
            var doc = new XmlDocument();
            var ourNode = XmlUtilities.GetDocumentNodeFromRawXml(ourXml, doc);
            var theirNode = XmlUtilities.GetDocumentNodeFromRawXml(theirXml, doc);
            var ancestorNode = XmlUtilities.GetDocumentNodeFromRawXml(ancestorXml, doc);

            var eventListener = new ListenerForUnitTests();
            var merger = new XmlMerger(mergeSituation)
                         	{
                                MergeStrategies = mergeStrategies
                         	};
            var retval = merger.Merge(eventListener, ourNode, theirNode, ancestorNode).OuterXml;
            Assert.AreSame(eventListener, merger.EventListener); // Make sure it never changes it, while we aren't looking, since at least one Merge method does that very thing.

            CheckMergeResults(retval, eventListener,
                xpathQueriesThatMatchExactlyOneNode, xpathQueriesThatReturnNull,
                expectedConflictCount, expectedConflictTypes,
                expectedChangesCount, expectedChangeTypes);

            return retval;
        }
Exemple #18
0
        /// <summary>
        /// <para>Before we attempt to compare a node with a corresponding one from another revision,
        /// we want to make sure that it is in a good state for matching its children with the children of the corresponding node.</para>
        ///
        /// <para>To do this, for each child, we allow the Finder which will be used to find a corresponding child in
        /// another revision to provide a query, which can be used to check whether the parent node has 'ambiguous' children,
        /// that is, groups of children which the finder would consider indistinguisable.</para>
        /// </summary>
        /// <remarks>
        /// This is recursive, since it moves on down to all child nodes.
        /// </remarks>
        public static void RemoveAmbiguousChildren(IMergeEventListener eventListener,
			MergeStrategies mergeStrategies,
			XmlNode parent)
        {
            if (parent == null || !parent.HasChildNodes || !RemoveAmbiguousChildNodes)
                return;

            var elementStrat = mergeStrategies.GetElementStrategy(parent);
            if (elementStrat.IsImmutable)
                return;
            var ambiguousNodes = new List<XmlNode>();
            var copyOfChildNodes = new List<XmlNode>(parent.ChildNodes.Count);
            copyOfChildNodes.AddRange(parent.ChildNodes.Cast<XmlNode>());

            foreach (var childNode in copyOfChildNodes)
            {
                var childNodeAsVariable = childNode;
                if (ambiguousNodes.Contains(childNodeAsVariable))
                    continue; // Already found it, so don't bother processing it again.

                elementStrat = mergeStrategies.GetElementStrategy(childNodeAsVariable);
                if (elementStrat.IsImmutable)
                    continue;
                var finder = elementStrat.MergePartnerFinder;
                if (!(finder is IFindMatchingNodesToMerge))
                    continue;
                var finderOfMultiples = (IFindMatchingNodesToMerge) finder;
                var matches = finderOfMultiples.GetMatchingNodes(childNodeAsVariable, parent).ToList();
                if (matches.Count < 2)
                    continue; // No duplicates were found, so keep going.

                // The following code implements the "DropAmbiguitiesAndAddErrorNote" option of a possible three in "AmbiguousSiblingPolicy"
                // TODO (maybe): If we ever implement the "ThrowException" option, then throw here instead of adding the warning and eating the ambiguities.
                // TODO (maybe): If we ever implement the "LiveWithIt" option, then just do a return at the start of this method, or don't bother calling the method at all.
                // Since they are ambiguities (at least as far as the finder is concerned),
                // we really only need one warning. Add the count, so the user knows how many there were, though.
                // Possible enhancement: Generate reports that go into the details of what might be different between the keeper and each ambiguous sibling.
                AddWarningToListener(eventListener,
                                     new MergeWarning(string.Format("Parent element '{0}' contains {1} ambiguous child elements. Only the first one is retained. Details: {2}.",
                                                                    parent.Name,
                                                                    matches.Count,
                                                                    finderOfMultiples.GetWarningMessageForAmbiguousNodes(matches[0]))));
                // Add all but the current one (the first one), so they can be removed in the next loop.
                ambiguousNodes.AddRange(matches.Where(match => match != childNodeAsVariable));
            }

            foreach (var ambiguousNode in ambiguousNodes)
            {
                // Remove all but the first one from the parent.
                parent.RemoveChild(ambiguousNode);
            }

            foreach (XmlNode childNode in parent.ChildNodes)
            {
                // Drill on down the child nodes to see if there are any other ambiguities in lower-level nodes.
                // Since the ambiguous nodes have been removed from parent, they won't get processed again.
                RemoveAmbiguousChildren(eventListener, mergeStrategies, childNode);
            }
        }
Exemple #19
0
        /// <summary>
        /// <para>Before we attempt to compare a node with a corresponding one from another revision,
        /// we want to make sure that it is in a good state for matching its children with the children of the corresponding node.</para>
        ///
        /// <para>To do this, for each child, we allow the Finder which will be used to find a corresponding child in
        /// another revision to provide a query, which can be used to check whether the parent node has 'ambiguous' children,
        /// that is, groups of children which the finder would consider indistinguisable.</para>
        /// </summary>
        /// <remarks>
        /// This is recursive, since it moves on down to all child nodes.
        /// </remarks>
        public static string RemoveAmbiguousChildren(IMergeEventListener eventListener,
			MergeStrategies mergeStrategies,
			string parent, string pathname)
        {
            if (!RemoveAmbiguousChildNodes)
                return parent;

            if (pathname.ToLowerInvariant().EndsWith("lift") || pathname.ToLowerInvariant().EndsWith("lift-ranges"))
            {
                parent = LiftSorter.FixBadTextElements(parent).ToString();
            }
            var parentNode = XmlUtilities.GetDocumentNodeFromRawXml(parent, new XmlDocument());
            RemoveAmbiguousChildren(
                eventListener,
                mergeStrategies,
                parentNode);
            return parentNode.OuterXml;
        }
Exemple #20
0
        /// <summary>
        /// <para>Before we attempt to compare a node with a corresponding one from another revision,
        /// we want to make sure that it is in a good state for matching its children with the children of the corresponding node.</para>
        /// 
        /// <para>To do this, for each child, we allow the Finder which will be used to find a corresponding child in
        /// another revision to provide a query, which can be used to check whether the parent node has 'ambiguous' children,
        /// that is, groups of children which the finder would consider indistinguisable.</para>
        /// </summary>
        /// <remarks>
        /// This is recursive, since it moves on down to all child nodes.
        /// </remarks>
        public static string RemoveAmbiguousChildren(IMergeEventListener eventListener,
			MergeStrategies mergeStrategies,
			string parent)
        {
            if (!RemoveAmbiguousChildNodes)
                return parent;
            var parentNode = XmlUtilities.GetDocumentNodeFromRawXml(parent, new XmlDocument());
            RemoveAmbiguousChildren(
                eventListener,
                mergeStrategies,
                parentNode);
            return parentNode.OuterXml;
        }
 internal static ElementStrategy AddSingletonElementType(MergeStrategies mergeStrategies, string name)
 {
     var strategy = new ElementStrategy(false)
                     {
                         MergePartnerFinder = new FindFirstElementWithSameName()
                     };
     mergeStrategies.SetStrategy(name, strategy);
     return strategy;
 }
        private static void AddPropertyStrategiesForClass(MergeStrategies strategiesForMerger, FdoClassInfo classInfo)
        {
            foreach (var propertyInfo in classInfo.AllProperties)
            {
                var isCustom = propertyInfo.IsCustomProperty;
                var propStrategy = isCustom
                                       ? CreateStrategyForKeyedElement(SharedConstants.Name, false)
                                       : CreateSingletonElementStrategy();
                switch (propertyInfo.DataType)
                {
                    // Block of object properties

                    case DataType.OwningAtomic:
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne;
                        break;
                    //case DataType.OwningCollection: // Nothing special done
                    //	break;
                    case DataType.OwningSequence:
                        if ((classInfo.ClassName == "CmPossibilityList" && propertyInfo.PropertyName == "Possibilities")
                            || (propertyInfo.PropertyName == "SubPossibilities" && classInfo.IsOrInheritsFrom("CmPossibility")))
                        {
                            // Order may or may not be significant in possibility lists and sublists, depending on whether the list is sorted.
                            propStrategy.ChildOrderPolicy = new PossibilityListOrderPolicy();
                        }
                        else
                        {
                            // Normally order is significant in owning sequences; no need to ask each child.
                            propStrategy.ChildOrderPolicy = new SignificantOrderPolicy();
                        }
                        break;
                    case DataType.ReferenceAtomic:
                        if (classInfo.ClassName == "LexSense" && propertyInfo.PropertyName == "MorphoSyntaxAnalysis")
                        {
                            propStrategy.ContextDescriptorGenerator = new PosContextGenerator();
                        }
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne;
                        break;
                    //case DataType.ReferenceCollection: // Nothing special done
                    //	break;
                    case DataType.ReferenceSequence:
                        // Trying to merge the Analyses of a segment is problematic. Best to go all-or-nothing, and ensure
                        // we get a conflict report if it fails.
                        if (classInfo.ClassName == "Segment" && propertyInfo.PropertyName == "Analyses")
                            propStrategy.IsAtomic = true;
                        break;

                    // Block of multi-somethings
                    // In model, but nothing special done at the property element level
                    //case DataType.MultiString:
                    //    break;
                    //case DataType.MultiUnicode:
                    //    break;

                    // Block of other property data types
                    case DataType.Binary:
                        propStrategy.IsAtomic = true;
                        break;
                    case DataType.Boolean:
                        // LT-13320 "Date of Event is lost after send/receive (data loss)"
                        // says these fields don't play nice as immutable.
                        //if (classInfo.ClassName == "CmPerson" || classInfo.ClassName == "RnGenericRec")
                        //	propStrategy.IsImmutable = true; // Surely DateOfBirth, DateOfDeath, and DateOfEvent are fixed. onced they happen. :-)
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero;
                        break;
                    //case DataType.Float: // Not used in model
                    //	break;
                    case DataType.GenDate:
                        // LT-13320 "Date of Event is lost after send/receive (data loss)"
                        // says these fields don't play nice as immutable.
                        //if (classInfo.ClassName == "CmPerson" || classInfo.ClassName == "RnGenericRec")
                        //	propStrategy.IsImmutable = true; // Surely DateOfBirth, DateOfDeath, and DateOfEvent are fixed. onced they happen. :-)
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero;
                        break;
                    case DataType.Guid:
                        if (classInfo.ClassName == "CmFilter" || classInfo.ClassName == "CmResource")
                            propStrategy.IsImmutable = true;
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero;
                        break;
                    case DataType.Integer: // Fall through
                        if (propertyInfo.PropertyName == "HomographNumber")
                        {
                            // Don't fret about conflicts in merging the homograph numbers.
                            propStrategy.AttributesToIgnoreForMerging.Add("val");
                        }
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero;
                        break;
                    //case DataType.Numeric: // Not used in model
                    //	break;
                    case DataType.String: // Contains one <Str> element
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne;
                        break;
                    case DataType.TextPropBinary:
                        propStrategy.ContextDescriptorGenerator = new StyleContextGenerator();
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne;
                        break;
                    case DataType.Time:
                        if (propertyInfo.PropertyName == "DateCreated")
                        {
                            propStrategy.IsImmutable = true;
                        }
                        else
                        {
                            // Suppress conflicts and change reports for other date time properties, which currently are all
                            // some variation on modify time, or most recent run time.
                            // For all of them, it is appropriate to just keep the most recent.
                            propStrategy.Premerger = new PreferMostRecentTimePreMerger();
                        }
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.Zero;
                        break;
                    case DataType.Unicode: // Contains one <Uni> element
                        propStrategy.NumberOfChildren = NumberOfChildrenAllowed.ZeroOrOne;
                        break;
                }
                strategiesForMerger.SetStrategy(
                    String.Format("{0}{1}_{2}", isCustom ? "Custom_" : "", classInfo.ClassName, propertyInfo.PropertyName), propStrategy);
            }
        }
        private static void MakeClassStrategy(MergeStrategies strategiesForMerger, FdoClassInfo classInfo, FieldWorkObjectContextGenerator defaultDescriptor)
        {
            Guard.AgainstNull(defaultDescriptor, "defaultDescriptor");

            // These values can be overridden or added to in the big switch, below.
            var classStrat = new ElementStrategy(false)
                {
                    ContextDescriptorGenerator = defaultDescriptor,
                    MergePartnerFinder = GuidKeyFinder,
                    IsAtomic = false
                };

            strategiesForMerger.SetStrategy(classInfo.ClassName, classStrat);

            // Try to keep these in alphbetical order, and where there are 'blocks', then try to keep the blocks in order.
            // That will make them easier to find.
            switch (classInfo.ClassName)
            {
                case "CmPossibilityList":
                    classStrat.ContextDescriptorGenerator = new PossibilityListContextGenerator();
                    break;
                case "FsClosedFeature":
                    classStrat.ContextDescriptorGenerator = new MultiLingualStringsContextGenerator("Phonological Features", "Name", "Abbreviation");
                    break;
                case "FsFeatStruc":
                    classStrat.IsAtomic = true;
                    break;
                case "LangProject":
                    classStrat.ContextDescriptorGenerator = new LanguageProjectContextGenerator();
                    break;
                case "LexEntry":
                    classStrat.ContextDescriptorGenerator = new LexEntryContextGenerator();
                    break;
                case "PhEnvironment":
                    classStrat.ContextDescriptorGenerator = new EnvironmentContextGenerator();
                    break;
                case "PhNCSegments":
                    classStrat.ContextDescriptorGenerator = new MultiLingualStringsContextGenerator("Natural Class", "Name", "Abbreviation");
                    break;
                case "ReversalIndexEntry":
                    classStrat.ContextDescriptorGenerator = new ReversalEntryContextGenerator();
                    break;
                case "RnGenericRec":
                    classStrat.ContextDescriptorGenerator = new RnGenericRecContextGenerator();
                    break;
                case "ScrBook":
                    classStrat.ContextDescriptorGenerator = new ScrBookContextGenerator();
                    break;
                case "ScrDraft":
                    // ScrDraft instances can only be added or removed, but not changed, according to John Wickberg (18 Jan 2012).
                    classStrat.IsImmutable = true;
                    break;
                case "ScrSection":
                    classStrat.ContextDescriptorGenerator = new ScrSectionContextGenerator();
                    break;
                case "ScrTxtPara": // Fall through.
                case "StTxtPara":
                    // This will never be used, since StTxtParas & ScrTxtParas are actually in an 'ownseq' element.
                    classStrat.Premerger = new StTxtParaPremerger();
                    // Didn't work, since StTxtParas & ScrTxtParas are actually in an 'ownseq' element.
                    // classStrat.IsAtomic = true;
                    break;
                case "Text":
                    classStrat.ContextDescriptorGenerator = new TextContextGenerator();
                    break;
                case "WfiWordform":
                    classStrat.ContextDescriptorGenerator = new WfiWordformContextGenerator();
                    break;

                // These should be all the subclasses of CmPossiblity. It's unfortuate to have to list them here;
                // OTOH, if we ever want special handling for any of them, we can easily add a special generator.
                // Note that these will not usually be found as strategies, since they are owned in owning sequences
                // and ownseq has its own item. However, they can be found by the default object context generator code,
                // which has a special case for ownseq.
                case "ChkTerm":
                case "CmAnthroItem":
                case "CmAnnotationDefn":
                case "CmCustomItem":
                case "CmLocation":
                case "CmPerson":
                case "CmPossibility":
                case "CmSemanticDomain":
                case "LexEntryType":
                case "LexRefType":
                case "MoMorphType":
                case "PartOfSpeech":
                case "PhPhonRuleFeat":
                    classStrat.ContextDescriptorGenerator = new PossibilityContextGenerator();
                    break;

                case "ConstChartRow":
                case "ConstChartWordGroup":
                case "DsConstChart":
                    classStrat.ContextDescriptorGenerator = new DiscourseChartContextGenerator();
                    break;
            }

            ((FieldWorkObjectContextGenerator)classStrat.ContextDescriptorGenerator).MergeStrategies = strategiesForMerger;
        }
        /// <summary>
        /// <para>Before we attempt to compare a node with a corresponding one from another revision,
        /// we want to make sure that it is in a good state for matching its children with the children of the corresponding node.</para>
        ///
        /// <para>To do this, for each child, we allow the Finder which will be used to find a corresponding child in
        /// another revision to provide a query, which can be used to check whether the parent node has 'ambiguous' children,
        /// that is, groups of children which the finder would consider indistinguisable.</para>
        /// </summary>
        /// <remarks>
        /// This is recursive, since it moves on down to all child nodes.
        /// </remarks>
        public static string RemoveAmbiguousChildren(IMergeEventListener eventListener,
			MergeStrategies mergeStrategies,
			string parent, string pathname)
        {
            if (!RemoveAmbiguousChildNodes)
                return parent;

            if (pathname.ToLowerInvariant().EndsWith("lift") || pathname.ToLowerInvariant().EndsWith("lift-ranges"))
            {
                var parentElement = XElement.Parse(parent);
                foreach (var misnamedElement in parentElement.Descendants("element"))
                {
                    misnamedElement.Name = "text";
                    misnamedElement.Attribute("name").Remove();
                }
                parent = parentElement.ToString();
            }
            var parentNode = XmlUtilities.GetDocumentNodeFromRawXml(parent, new XmlDocument());
            RemoveAmbiguousChildren(
                eventListener,
                mergeStrategies,
                parentNode);
            return parentNode.OuterXml;
        }