/// <summary> /// Return the ElementStrategy instance for the given <param name="element"/>, or a default instance set up like this: /// ElementStrategy def = new ElementStrategy(true);//review: this says the default is to consider order relevant /// def.MergePartnerFinder = new FindByEqualityOfTree(); /// </summary> public ElementStrategy GetElementStrategy(XmlNode element) { var def = new ElementStrategy(true) { MergePartnerFinder = new FindByEqualityOfTree() }; return def; }
public static ElementStrategy CreateForKeyedElementInList(string keyAttributeName) { var strategy = new ElementStrategy(true) { MergePartnerFinder = new FindByKeyAttributeInList(keyAttributeName) }; return(strategy); }
/// <summary> /// Declare that there can only be a single element with this name in a list of children /// </summary> public static ElementStrategy CreateSingletonElement() { var strategy = new ElementStrategy(false) { MergePartnerFinder = new FindFirstElementWithSameName() }; return(strategy); }
/// <summary> /// Return the ElementStrategy instance for the given <param name="element"/>, or a default instance set up like this: /// ElementStrategy def = new ElementStrategy(true);//review: this says the default is to consider order relevant /// def.MergePartnerFinder = new FindByEqualityOfTree(); /// </summary> public ElementStrategy GetElementStrategy(XmlNode element) { var def = new ElementStrategy(true) { MergePartnerFinder = new FindByEqualityOfTree() }; return(def); }
public static ElementStrategy CreateForKeyedElement(string keyAttributeName, bool orderIsRelevant) { var strategy = new ElementStrategy(orderIsRelevant) { MergePartnerFinder = new FindByKeyAttribute(keyAttributeName) }; return(strategy); }
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; }
/// <summary> /// Gets the collection of element merge strategies. /// </summary> public MergeStrategies GetStrategies() { var merger = new XmlMerger(new MergeSituation(null, null, null, null, null, MergeOrder.ConflictHandlingModeChoices.WeWin)); var def = new ElementStrategy(true) { MergePartnerFinder = new FindByEqualityOfTree() }; merger.MergeStrategies.SetStrategy("def", def); return merger.MergeStrategies; }
private static ElementStrategy MakeClassStrategy(FieldWorkObjectContextGenerator descriptor, MergeStrategies strategies) { var classStrat = new ElementStrategy(false) { MergePartnerFinder = GuidKey, ContextDescriptorGenerator = descriptor, IsAtomic = false }; descriptor.MergeStrategies = strategies; return classStrat; }
/// <summary> /// Gets the collection of element merge strategies. /// </summary> public MergeStrategies GetStrategies() { var merger = new XmlMerger(new MergeSituation(null, null, null, null, null, MergeOrder.ConflictHandlingModeChoices.WeWin)); var def = new ElementStrategy(true) { MergePartnerFinder = new FindByEqualityOfTree() }; merger.MergeStrategies.SetStrategy("def", def); return(merger.MergeStrategies); }
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. }
public MergeStrategies() { ElementStrategies = new Dictionary <string, ElementStrategy>(); ElementStrategy s = new ElementStrategy(true); //review: this says the default is to consider order relevant s.MergePartnerFinder = new FindTextDumb(); SetStrategy("_" + XmlNodeType.Text, s); ElementStrategy def = new ElementStrategy(true); //review: this says the default is to consider order relevant def.MergePartnerFinder = new FindByEqualityOfTree(); SetStrategy("_defaultElement", def); ElementToMergeStrategyKeyMapper = new DefaultElementToMergeStrategyKeyMapper(); }
/// <summary> /// Bootstrap a merger for the new-styled (nested) files. /// </summary> /// <remarks> /// 1. A generic 'header' element will be handled, although it may not appear in the file. /// 2. All classes will be included. /// 3. Merge strategies for class properties (regular or custom) will have keys of "classname+propname" to make them unique, system-wide. /// </remarks> private static void BootstrapSystem(MetadataCache metadataCache, XmlMerger merger) { merger.MergeStrategies.ElementToMergeStrategyKeyMapper = new FieldWorksElementToMergeStrategyKeyMapper(); var sharedElementStrategies = new Dictionary<string, ElementStrategy>(); CreateSharedElementStrategies(sharedElementStrategies); var strategiesForMerger = merger.MergeStrategies; ContextGen.MergeStrategies = strategiesForMerger; foreach (var sharedKvp in sharedElementStrategies) strategiesForMerger.SetStrategy(sharedKvp.Key, sharedKvp.Value); var customPropDefnStrat = new ElementStrategy(false) { MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> { SharedConstants.Name, SharedConstants.Class }), ContextDescriptorGenerator = new FieldWorksCustomPropertyContextGenerator(), IsAtomic = true, NumberOfChildren = NumberOfChildrenAllowed.Zero }; strategiesForMerger.SetStrategy(SharedConstants.CustomField, customPropDefnStrat); var headerStrategy = CreateSingletonElementType(false); headerStrategy.ContextDescriptorGenerator = ContextGen; strategiesForMerger.SetStrategy(SharedConstants.Header, headerStrategy); // There are two abstract class names used: CmAnnotation and DsChart. // Chorus knows how to find the matching element for these, as they use <CmAnnotation class='concreteClassname'. // So, add a keyed strategy for each of them. var keyedStrat = ElementStrategy.CreateForKeyedElement(SharedConstants.GuidStr, false); keyedStrat.AttributesToIgnoreForMerging.Add(SharedConstants.Class); keyedStrat.AttributesToIgnoreForMerging.Add(SharedConstants.GuidStr); strategiesForMerger.SetStrategy(SharedConstants.CmAnnotation, keyedStrat); keyedStrat = ElementStrategy.CreateForKeyedElement(SharedConstants.GuidStr, false); keyedStrat.AttributesToIgnoreForMerging.Add(SharedConstants.Class); keyedStrat.AttributesToIgnoreForMerging.Add(SharedConstants.GuidStr); strategiesForMerger.SetStrategy(SharedConstants.DsChart, keyedStrat); foreach (var classInfo in metadataCache.AllConcreteClasses) { MakeClassStrategy(strategiesForMerger, classInfo, ContextGen); AddPropertyStrategiesForClass(strategiesForMerger, classInfo); } }
internal static void SetupElementStrategies(XmlMerger merger) { merger.MergeStrategies.ElementToMergeStrategyKeyMapper = new LdmlElementToMergeStrategyKeyMapper(); // See: Palaso repo: SIL.WritingSystems\LdmlDataMapper.cs var strategy = ElementStrategy.CreateSingletonElement(); strategy.ContextDescriptorGenerator = new LdmlContextGenerator(); merger.MergeStrategies.SetStrategy("ldml", strategy); // Child elements of ldml root. merger.MergeStrategies.SetStrategy("identity", ElementStrategy.CreateSingletonElement()); // Child elements of "identity". merger.MergeStrategies.SetStrategy("version", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("generation", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("language", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("script", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("territory", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("variant", ElementStrategy.CreateSingletonElement()); // sil:special can occur several times throughout the file merger.MergeStrategies.SetStrategy("special_xmlns:sil", new ElementStrategy(false) { MergePartnerFinder = new FindByMatchingAttributeNames(new HashSet<string> { "xmlns:sil" }) }); merger.MergeStrategies.SetStrategy("sil:identity", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("localeDisplayNames", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("layout", ElementStrategy.CreateSingletonElement()); // Child element of "layout". merger.MergeStrategies.SetStrategy("orientation", new ElementStrategy(false) { IsAtomic = true, MergePartnerFinder = new FindFirstElementWithSameName() }); merger.MergeStrategies.SetStrategy("contextTransforms", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("characters", new ElementStrategy(false) { IsAtomic = true, MergePartnerFinder = new FindFirstElementWithSameName() }); merger.MergeStrategies.SetStrategy("delimiters", new ElementStrategy(false) { IsAtomic = true, MergePartnerFinder = new FindFirstElementWithSameName() }); merger.MergeStrategies.SetStrategy("dates", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("numbers", new ElementStrategy(false) { IsAtomic = true, MergePartnerFinder = new FindFirstElementWithSameName() }); merger.MergeStrategies.SetStrategy("units", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("listPatterns", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("collations", ElementStrategy.CreateSingletonElement()); // Child element of collations strategy = new ElementStrategy(false) { IsAtomic = true, // I (RBR) think it would be suicidal to try and merge this element. MergePartnerFinder = new FindByKeyAttribute("type") }; merger.MergeStrategies.SetStrategy("collation", strategy); // Child of 'collation' element (They exist, but we don't care what they are, as long as the parent is 'atomic'. merger.MergeStrategies.SetStrategy("posix", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("segmentations", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("rbnf", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("metadata", ElementStrategy.CreateSingletonElement()); // See: Palaso repo: SIL.WritingSystems\LdmlDataMapper.cs // There currently are up to three 'special' child elements of the 'ldml' root element. // Special "xmlns:palaso" attr strategy = new ElementStrategy(false) { IsAtomic = true, // May not be needed... MergePartnerFinder = new FindByMatchingAttributeNames(new HashSet<string> { "xmlns:palaso" }) }; merger.MergeStrategies.SetStrategy("special_xmlns:palaso", strategy); /* Not needed, as long as the parent is 'atomic'. // Children of 'special' xmlns:palaso // palaso:abbreviation merger.MergeStrategies.SetStrategy("palaso:abbreviation", ElementStrategy.CreateSingletonElement()); // palaso:defaultFontFamily merger.MergeStrategies.SetStrategy("palaso:defaultFontFamily", ElementStrategy.CreateSingletonElement()); // palaso:defaultFontSize merger.MergeStrategies.SetStrategy("palaso:defaultFontSize", ElementStrategy.CreateSingletonElement()); // palaso:defaultKeyboard merger.MergeStrategies.SetStrategy("palaso:defaultKeyboard", ElementStrategy.CreateSingletonElement()); // palaso:isLegacyEncoded merger.MergeStrategies.SetStrategy("palaso:isLegacyEncoded", ElementStrategy.CreateSingletonElement()); // palaso:languageName merger.MergeStrategies.SetStrategy("palaso:languageName", ElementStrategy.CreateSingletonElement()); // palaso:spellCheckingId merger.MergeStrategies.SetStrategy("palaso:spellCheckingId", ElementStrategy.CreateSingletonElement()); // palaso:version merger.MergeStrategies.SetStrategy("palaso:version", ElementStrategy.CreateSingletonElement()); */ // See: Palaso repo: SIL.WritingSystems\LdmlDataMapper.cs // special "xmlns:palaso2" attr: want to merge knownKeyboards child. So the root element is not atomic. strategy = new ElementStrategy(false) { MergePartnerFinder = new FindByMatchingAttributeNames(new HashSet<string> {"xmlns:palaso2"}) }; merger.MergeStrategies.SetStrategy("special_xmlns:palaso2", strategy); // Children of 'strategy' xmlns:palaso2 // palaso2:knownKeyboards: merger.MergeStrategies.SetStrategy("palaso2:knownKeyboards", ElementStrategy.CreateSingletonElement()); // Multiple children of "palaso2:knownKeyboards" element strategy = new ElementStrategy(false) { MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> {"layout", "locale"}) }; merger.MergeStrategies.SetStrategy("palaso2:keyboard", strategy); merger.MergeStrategies.SetStrategy("palaso2:version", ElementStrategy.CreateSingletonElement()); // Special "xmlns:fw" attr (See FW source file: Src\Common\CoreImpl\PalasoWritingSystemManager.cs strategy = new ElementStrategy(false) { IsAtomic = true, // Really is needed. At least it is for some child elements. MergePartnerFinder = new FindByMatchingAttributeNames(new HashSet<string> { "xmlns:fw" }) }; merger.MergeStrategies.SetStrategy("special_xmlns:fw", strategy); /* Not needed, as long as the parent is 'atomic'. // Children for 'special' xmlns:fw merger.MergeStrategies.SetStrategy("fw:defaultFontFeatures", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:graphiteEnabled", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:legacyMapping", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:matchedPairs", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:punctuationPatterns", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:quotationMarks", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:regionName", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:scriptName", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:validChars", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:variantName", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("fw:windowsLCID", ElementStrategy.CreateSingletonElement()); */ // Children for top level 'special' xmlns:sil merger.MergeStrategies.SetStrategy("sil:external-resources", ElementStrategy.CreateSingletonElement()); merger.MergeStrategies.SetStrategy("sil:kbd", new ElementStrategy(false) { IsAtomic = true, MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string>{"id", "alt"}) } ); merger.MergeStrategies.SetStrategy("sil:font", new ElementStrategy(false) { IsAtomic = true, MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string>{"name", "alt"}) } ); merger.MergeStrategies.SetStrategy("sil:spellcheck", new ElementStrategy(false) { IsAtomic = true, MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string>{"type", "alt"}) } ); merger.MergeStrategies.SetStrategy("sil:transform", new ElementStrategy(false) { IsAtomic = true, MergePartnerFinder = new FindByMultipleKeyAttributes(new List<string> { "from", "to", "type", "direction", "function", "alt" }) } ); }
public MergeStrategies() { ElementStrategies = new Dictionary<string, ElementStrategy>(); ElementStrategy s = new ElementStrategy(true);//review: this says the default is to consider order relevant s.MergePartnerFinder = new FindTextDumb(); SetStrategy("_"+XmlNodeType.Text, s); ElementStrategy def = new ElementStrategy(true);//review: this says the default is to consider order relevant def.MergePartnerFinder = new FindByEqualityOfTree(); SetStrategy("_defaultElement", def); ElementToMergeStrategyKeyMapper = new DefaultElementToMergeStrategyKeyMapper(); }
public void UsingWith_NumberOfChildrenAllowed_ZeroOrMore_Throws() { var strategy = new ElementStrategy(false) { NumberOfChildren = NumberOfChildrenAllowed.ZeroOrMore }; var doc = new XmlDocument(); var parent = doc.CreateNode(XmlNodeType.Element, "somenode", null); Assert.Throws<InvalidOperationException>(() => MergeLimitedChildrenService.Run(new XmlMerger(new NullMergeSituation()), strategy, ref parent, parent, parent)); }
private static XmlMerger GetMerger(MergeSituation mergeSituation, out ListenerForUnitTests listener) { var elementStrategy = new ElementStrategy(false) { IsAtomic = true }; var merger = new XmlMerger(mergeSituation); merger.MergeStrategies.SetStrategy("topatomic", elementStrategy); listener = new ListenerForUnitTests(); merger.EventListener = listener; return merger; }
/// <summary> /// Declare that there can only be a single element with this name in a list of children /// </summary> public static ElementStrategy CreateSingletonElement() { var strategy = new ElementStrategy(false) { MergePartnerFinder = new FindFirstElementWithSameName() }; return strategy; }
private static void AddTranslationStrategy(MergeStrategies mergeStrategies) { var strategy = new ElementStrategy(false) { MergePartnerFinder = new OptionalKeyAttrFinder("type", new FormMatchingFinder()) }; mergeStrategies.SetStrategy("translation", strategy); }
public void CanSetToTrue() { var elementStrategy = new ElementStrategy(false) { IsAtomic = true }; Assert.IsTrue(elementStrategy.IsAtomic); }
public void PreMergeCalledBeforeMerging() { string red = @"<a/>"; string ancestor = red; string blue = @"<a> <b key='one'> <c>first</c> </b> </a>"; var specialMergeStrategies = new Dictionary<string, ElementStrategy>(); var elementStrat = new ElementStrategy(true) { Premerger = new SillyPremerger() }; specialMergeStrategies["a"] = elementStrat; CheckOneWay(red, blue, ancestor, new NullMergeSituation(), specialMergeStrategies, (Action<string, ElementStrategy>)null, "a[@silly='nonsense']/b[@key='one']/c[text()='first']"); }
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 SetStrategy(string key, ElementStrategy strategy) { ElementStrategies[key] = strategy; _elementStrategyKeys.Add(key); }
public void UsingWith_NumberOfChildrenAllowed_Zero_ThrowsWhenTheirsHasChildNode() { var strategy = new ElementStrategy(false) { NumberOfChildren = NumberOfChildrenAllowed.Zero }; var doc = new XmlDocument(); var theirs = doc.CreateNode(XmlNodeType.Element, "somenode", null); var theirChild = doc.CreateNode(XmlNodeType.Element, "child", null); theirs.AppendChild(theirChild); var ours = doc.CreateNode(XmlNodeType.Element, "somenode", null); var ancestor = doc.CreateNode(XmlNodeType.Element, "somenode", null); Assert.Throws<InvalidOperationException>(() => MergeLimitedChildrenService.Run(new XmlMerger(new NullMergeSituation()), strategy, ref ours, theirs, ancestor)); }
public static void Run(XmlMerger merger, ElementStrategy strategy, ref XmlNode ours, XmlNode theirs, XmlNode ancestor) { // All routes tested in this method. Guard.AgainstNull(merger, "merger"); // Route tested. Guard.AgainstNull(strategy, "strategy"); // Route tested. if (ours == null && theirs == null && ancestor == null) { throw new ArgumentNullException(); // Route tested. } if (XmlUtilities.IsTextLevel(ours, theirs, ancestor)) { // Route tested. new MergeTextNodesMethod(merger, merger.MergeStrategies.GetElementStrategy(ours ?? theirs ?? ancestor), new HashSet <XmlNode>(), ref ours, new List <XmlNode>(), theirs, new List <XmlNode>(), ancestor, new List <XmlNode>()).Run(); return; } List <XmlNode> ourChildren; List <XmlNode> theirChildren; List <XmlNode> ancestorChildren; switch (strategy.NumberOfChildren) { default: throw new InvalidOperationException("Using strategy with NumberOfChildren property of NumberOfChildrenAllowed.ZeroOrMore is not legal."); // Route tested. case NumberOfChildrenAllowed.Zero: ourChildren = GetElementChildren(ours).ToList(); if (ourChildren.Any()) { throw new InvalidOperationException("Using strategy with NumberOfChildren property of NumberOfChildrenAllowed.Zero is not legal, when there are child element nodes."); // Route tested. } theirChildren = GetElementChildren(theirs).ToList(); if (theirChildren.Any()) { throw new InvalidOperationException("Using strategy with NumberOfChildren property of NumberOfChildrenAllowed.Zero is not legal, when there are child element nodes."); // Route tested. } ancestorChildren = GetElementChildren(ancestor).ToList(); if (ancestorChildren.Any()) { throw new InvalidOperationException("Using strategy with NumberOfChildren property of NumberOfChildrenAllowed.Zero is not legal, when there are child element nodes."); // Route tested. } // Don't merge deeper than merging the attributes, since there aren't supposed to be any children. // Already done by caller MergeXmlAttributesService.MergeAttributes(merger, ref ours, theirs, ancestor); // Route tested. break; case NumberOfChildrenAllowed.ZeroOrOne: ourChildren = GetElementChildren(ours).ToList(); if (ourChildren.Count > 1) { throw new InvalidOperationException("Using strategy with NumberOfChildren property of NumberOfChildrenAllowed.ZeroOrOne is not legal, when there are multiple child nodes."); // Route tested. } theirChildren = GetElementChildren(theirs).ToList(); if (theirChildren.Count > 1) { throw new InvalidOperationException("Using strategy with NumberOfChildren property of NumberOfChildrenAllowed.ZeroOrOne is not legal, when there are multiple child nodes."); // Route tested. } ancestorChildren = GetElementChildren(ancestor).ToList(); if (ancestorChildren.Count > 1) { throw new InvalidOperationException("Using strategy with NumberOfChildren property of NumberOfChildrenAllowed.ZeroOrOne is not legal, when there are child element nodes."); // Route tested. } // Already done by caller MergeXmlAttributesService.MergeAttributes(merger, ref ours, theirs, ancestor); if (!ourChildren.Any() && !theirChildren.Any() && ancestor != null) { return; // Route tested. } // The return value of Run may be the original 'ours', a replacement for it, or null. ours = Run(merger, ours, theirs, ancestor); // Route tested. break; } }
public static ElementStrategy CreateForKeyedElement(string keyAttributeName, bool orderIsRelevant) { var strategy = new ElementStrategy(orderIsRelevant) { MergePartnerFinder = new FindByKeyAttribute(keyAttributeName) }; return strategy; }
/// <summary> /// Put in a special context generator for 'b', the element that is deleted. /// This should be used to generate the HTML. /// </summary> /// <param name="key"></param> /// <param name="strategy"></param> private void AddContextGenForB(string key, ElementStrategy strategy) { if (key != "b") return; strategy.ContextDescriptorGenerator = new EditDeleteContextGenerator(); }
internal static ElementStrategy AddSingletonElementType(MergeStrategies mergeStrategies, string name) { var strategy = new ElementStrategy(false) { MergePartnerFinder = new FindFirstElementWithSameName() }; mergeStrategies.SetStrategy(name, strategy); return 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); }
/// <summary> /// Remove from ancestorKeepers any node that does not correspond to anything (both deleted) /// Remove from ancestorKeepers and theirKeepers any pair that correspond to each other but not to anything in ours. Report conflict (delete/edit) if pair not identical. /// Remove from ancestorKeepers and ourKeepers any pair that correspond to each other and are identical, but don't correspond to anything in theirs (they deleted) /// Report conflict (edit/delete) on any pair that correspond in ours and ancestor, but nothing in theirs, and that are NOT identical. (but keep them...we win) /// </summary> private void DoDeletions() { // loop over a copy of the list, since we may modify ancestorKeepers. List <XmlNode> loopSource = new List <XmlNode>(_childrenOfAncestorKeepers); var ourChildSet = new HashSet <XmlNode>(_ours == null ? new XmlNode[0] : _ours.ChildNodes.Cast <XmlNode>()); var theirChildSet = new HashSet <XmlNode>(_theirs == null ? new XmlNode[0] : _theirs.ChildNodes.Cast <XmlNode>()); foreach (XmlNode ancestorChild in loopSource) { ElementStrategy mergeStrategy = _merger.MergeStrategies.GetElementStrategy(ancestorChild); IFindNodeToMerge finder = mergeStrategy.MergePartnerFinder; XmlNode ourChild = finder.GetNodeToMerge(ancestorChild, _ours, ourChildSet); XmlNode theirChild = finder.GetNodeToMerge(ancestorChild, _theirs, theirChildSet); var extantNode = ancestorChild ?? ourChild ?? theirChild; if (extantNode is XmlCharacterData) { return; // Already done. } if (XmlUtilities.IsTextLevel(ourChild, theirChild, ancestorChild)) { new MergeTextNodesMethod(_merger, mergeStrategy, _skipInnerMergeFor, ref ourChild, _childrenOfOurKeepers, theirChild, _childrenOfTheirKeepers, ancestorChild, _childrenOfAncestorKeepers).DoDeletions(); } else if (ourChild == null) { // We deleted it. if (theirChild == null) { // We both deleted it. Forget it ever existed. // Route tested: MergeChildrenMethodTests. _merger.EventListener.ChangeOccurred(new XmlBothDeletionChangeReport(_merger.MergeSituation.PathToFileInRepository, ancestorChild)); _childrenOfAncestorKeepers.Remove(ancestorChild); } else { if (!XmlUtilities.AreXmlElementsEqual(ancestorChild, theirChild)) { // We deleted, they modified, report conflict. if (theirChild.NodeType == XmlNodeType.Element) { // Route tested (XmlMergerTests). _merger.ConflictOccurred( new RemovedVsEditedElementConflict(theirChild.Name, null, theirChild, ancestorChild, _merger.MergeSituation, _merger.MergeStrategies.GetElementStrategy(theirChild), _merger.MergeSituation.BetaUserId), theirChild); _skipInnerMergeFor.Add(theirChild); } else { // Never used. But then, there isn't plain text in an xml file. _merger.ConflictOccurred( new RemovedVsEditedTextConflict(null, theirChild, ancestorChild, _merger.MergeSituation, _merger.MergeSituation.BetaUserId)); _skipInnerMergeFor.Add(theirChild); } _childrenOfAncestorKeepers.Remove(ancestorChild); //review hatton added dec 2009, wanting whoever edited it to win (previously "we" always won) } else { //We deleted it, they didn't edit it. So just make it go away. // Route tested in TextElementMergeTests, MergeChildrenMethod_DiffOnlyTests, XmlMergerTests _merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(_merger.MergeSituation.PathToFileInRepository, ancestorChild, theirChild)); _childrenOfAncestorKeepers.Remove(ancestorChild); _childrenOfTheirKeepers.Remove(theirChild); } } } else if (theirChild == null) { // they deleted it (and we didn't) if (XmlUtilities.AreXmlElementsEqual(ancestorChild, ourChild)) { // We didn't touch it, allow their deletion to go forward, forget it existed. // Route tested (XmlMergerTests). _merger.EventListener.ChangeOccurred(new XmlDeletionChangeReport(_merger.MergeSituation.PathToFileInRepository, ancestorChild, ourChild)); _childrenOfAncestorKeepers.Remove(ancestorChild); _childrenOfOurKeepers.Remove(ourChild); } else { // We changed it, ignore their deletion and report conflict. if (ourChild.NodeType == XmlNodeType.Element) { // Route tested (XmlMergerTests). _merger.ConflictOccurred( new EditedVsRemovedElementConflict(ourChild.Name, ourChild, null, ancestorChild, _merger.MergeSituation, _merger.MergeStrategies.GetElementStrategy(ourChild), _merger.MergeSituation.AlphaUserId), ourChild); _skipInnerMergeFor.Add(ourChild); } else { // Never used. But then, there isn't plain text in an xml file. _merger.ConflictOccurred( new EditedVsRemovedTextConflict(ourChild, null, ancestorChild, _merger.MergeSituation, _merger.MergeSituation.AlphaUserId)); _skipInnerMergeFor.Add(ourChild); } } } } }
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 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; }
public void DefaultIsFalse() { var elementStrategy = new ElementStrategy(false); Assert.IsFalse(elementStrategy.IsAtomic); }
public void UsingWith_NumberOfChildrenAllowed_Zero_DoesNotThrowWhenParentHasCommentChildNode() { var strategy = new ElementStrategy(false) { NumberOfChildren = NumberOfChildrenAllowed.Zero }; var doc = new XmlDocument(); var parent = doc.CreateNode(XmlNodeType.Element, "somenode", null); var comment = doc.CreateNode(XmlNodeType.Comment, "Some comment.", null); parent.AppendChild(comment); Assert.DoesNotThrow(() => MergeLimitedChildrenService.Run(new XmlMerger(new NullMergeSituation()), strategy, ref parent, parent, parent)); }
private static XmlMerger GetMerger(out ListenerForUnitTests listener, bool isAtomic) { var elementStrategy = new ElementStrategy(false) { IsAtomic = isAtomic }; var merger = new XmlMerger(new NullMergeSituation()); merger.MergeStrategies.SetStrategy("topatomic", elementStrategy); listener = new ListenerForUnitTests(); merger.EventListener = listener; return merger; }
public static ElementStrategy CreateForKeyedElementInList(string keyAttributeName) { var strategy = new ElementStrategy(true) { MergePartnerFinder = new FindByKeyAttributeInList(keyAttributeName) }; return strategy; }
private static void AddKeyedElementType(IDictionary<string, ElementStrategy> sharedElementStrategies, string elementName, IFindNodeToMerge findBykeyAttribute, bool orderOfTheseIsRelevant, bool isAtomic) { var strategy = new ElementStrategy(orderOfTheseIsRelevant) { MergePartnerFinder = findBykeyAttribute, ContextDescriptorGenerator = ContextGen, IsAtomic = isAtomic }; sharedElementStrategies.Add(elementName, strategy); }
private static ElementStrategy CreateSingletonElementType(bool orderOfTheseIsRelevant) { var strategy = new ElementStrategy(orderOfTheseIsRelevant) { MergePartnerFinder = SameNameFinder, ContextDescriptorGenerator = ContextGen }; return strategy; }
/// <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; }
private void DoTextMerge(ref XmlNode ours, XmlNode theirs, XmlNode ancestor, ElementStrategy elementStrat) { new MergeTextNodesMethod(this, elementStrat, new HashSet <XmlNode>(), ref ours, new List <XmlNode>(), theirs, new List <XmlNode>(), ancestor, new List <XmlNode>()).Run(); }