public static LocalTerm CreateTermLinkUsingId(LocalTerm sourceTerm, bool isPinnedRoot = false) { if (!sourceTerm.IsSourceTerm) { throw new InvalidOperationException("Cannot create a link to a term with IsSourceTerm=false"); } return(LocalTerm.CreateTermLinkUsingId(sourceTerm.Id, sourceTerm.DefaultLanguageLcid, sourceTerm.Name, isPinnedRoot)); }
/// <summary> /// Returns the concatenated names of this term's parents, followed by this term. /// For example, if A has child term B, which has child term C, then the path is "A;B;C". /// </summary> public string GetPath() { LocalTerm parentTerm = this.ParentItem as LocalTerm; if (parentTerm == null) { return(this.Name); } return(parentTerm.GetPath() + ";" + this.Name); }
private LocalTerm(int defaultLanguageLcid, string termLinkSourcePath, bool isPinnedRoot) : base(Guid.Empty, defaultLanguageLcid) { ToolkitUtilities.ConfirmNotNull(termLinkSourcePath, "termLinkSourcePath"); this.sharedDataIfSourceTerm = null; this.termLinkData = new TermLinkData(); this.termLinkData.TermLinkSourcePathParts = LocalTerm.ParseTermLinkSourcePath(termLinkSourcePath); Debug.Assert(this.TermKind == LocalTermKind.TermLinkUsingPath); }
private SharedData GetSharedDataFromSourceTerm(bool exceptionIfMissing) { LocalTerm sourceTerm = this.SourceTerm; if (sourceTerm == null) { if (exceptionIfMissing) { throw new InvalidOperationException( "This operation cannot be performed because the source term is not part of the tree"); } return(null); } Debug.Assert(sourceTerm.sharedDataIfSourceTerm != null); return(sourceTerm.sharedDataIfSourceTerm); }
private void AddSubtreeToTable(LocalTaxonomyItem rootItem) { foreach (LocalTaxonomyItem localItem in ToolkitUtilities.GetPreorder(rootItem, (LocalTaxonomyItem x) => x.ChildItems)) { LocalTerm localTerm = localItem as LocalTerm; if (localTerm != null && localItem.Id != Guid.Empty) { // Add localTerm to the table List <LocalTerm> termList = null; if (!this.termsByGuid.TryGetValue(localTerm.Id, out termList)) { // Create the missing list termList = new List <LocalTerm>(); this.termsByGuid.Add(localTerm.Id, termList); } // Add the localTerm to the list if (localTerm.IsSourceTerm) { for (int i = 0; i < termList.Count; ++i) { if (termList[i].IsSourceTerm) { throw new InvalidOperationException(string.Format( "The term \"{0}\" cannot be the source term in two different term sets (TermId={1})", localTerm.Name, localTerm.Id)); } } // Source term is first in the list termList.Insert(0, localTerm); } else { termList.Add(localTerm); } } } }
/// <summary> /// Compares otherTerm's labels with this term's labels to see if there are any conflicts. /// A conflict occurs if the default labels (i.e. term names) are equal for a given language LCID. /// Note that we compare all LCIDs from both terms; if a term does not have a default label /// for a given LCID, then we fallback to the default language. (Recall that the "term name" /// is the "default label" for each language, and there is also a "default language" for /// the term store.) /// /// This check can also consider a proposedNewLabelForOtherTerm, which allows us to detect /// problems that would be introduced by adding/changing the otherTerm, before the change /// is performed. /// </summary> /// <returns> /// An "objection" (i.e. error message) if there is a conflict, or null otheriwse. /// </returns> internal string ExplainHasLabelConflictWith(LocalTerm otherTerm, LocalTermLabel proposedNewLabelForOtherTerm = null) { Debug.Assert(this.TermKind == LocalTermKind.NormalTerm); Debug.Assert(otherTerm.TermKind == LocalTermKind.NormalTerm); // The proposedNewLabelForOtherTerm only affects this comparison if it is the default label for a language // (i.e. we don't care about synonyms) if (proposedNewLabelForOtherTerm != null && !proposedNewLabelForOtherTerm.IsDefault) { proposedNewLabelForOtherTerm = null; } SharedData thisSharedData = this.GetSharedDataFromSourceTerm(exceptionIfMissing: true); SharedData otherSharedData = otherTerm.GetSharedDataFromSourceTerm(exceptionIfMissing: true); foreach (int lcid in // Take the union of the LCIDs from both terms, sorted in increasing order, // but compare the default language first new[] { this.DefaultLanguageLcid } .Union( thisSharedData.LabelsByLcid.Keys .Union(otherSharedData.LabelsByLcid.Keys) .Where(x => x != this.DefaultLanguageLcid) .OrderBy(x => x) .Distinct() )) { string thisName = this.GetNameWithDefault(lcid); string otherName = otherTerm.GetNameWithDefaultForConflict(otherSharedData, lcid, proposedNewLabelForOtherTerm); if (thisName.Equals(otherName, StringComparison.OrdinalIgnoreCase)) { return("The term name \"" + otherName + "\" is already in use by a sibling term" + " (LCID=" + lcid + ")"); } } return(null); }
private void ProcessTerm(XElement xmlNode, LocalTermContainer parentTermContainer, List <Guid> parentInOrderList, bool isTermLink) { LocalTerm term; Guid id = this.GetGuidAttributeValue(xmlNode, TaxmlSpec.IdToken) ?? Guid.Empty; if (isTermLink) { string nameHint = this.GetAttributeValue(xmlNode, TaxmlSpec.NameHintToken) ?? ""; string termLinkSourcePath = this.GetAttributeValue(xmlNode, TaxmlSpec.TermLinkSourcePathToken) ?? ""; if (id == Guid.Empty && string.IsNullOrWhiteSpace(termLinkSourcePath)) { throw new ParseException( "TermLink elements must have either the ID attribute or the TermLinkSourcePath attribute", xmlNode); } if (termLinkSourcePath.Length > 0) { term = LocalTerm.CreateTermLinkUsingPath(parentTermContainer.DefaultLanguageLcid, termLinkSourcePath); } else { term = LocalTerm.CreateTermLinkUsingId(id, parentTermContainer.DefaultLanguageLcid, nameHint); } } else { string name = this.GetRequiredAttributeValue(xmlNode, TaxmlSpec.NameToken); term = LocalTerm.CreateTerm(id, name, parentTermContainer.DefaultLanguageLcid); } this.ReadTaxmlComments(xmlNode, term); bool?isAvailableForTagging = this.GetBooleanAttributeValue(xmlNode, TaxmlSpec.IsAvailableForTaggingToken); if (isAvailableForTagging.HasValue) { term.IsAvailableForTagging = isAvailableForTagging.Value; } if (isTermLink) { bool?isPinnedRoot = this.GetBooleanAttributeValue(xmlNode, TaxmlSpec.IsPinnedRootToken); if (isPinnedRoot.HasValue) { term.IsPinnedRoot = isPinnedRoot.Value; } } else { string owner = this.GetAttributeValue(xmlNode, TaxmlSpec.OwnerToken); if (owner != null) { term.Owner = owner; } bool?isDeprecated = this.GetBooleanAttributeValue(xmlNode, TaxmlSpec.IsDeprecatedToken); if (isDeprecated.HasValue) { term.IsDeprecated = isDeprecated.Value; } } bool inOrder = this.GetBooleanAttributeValue(xmlNode, TaxmlSpec.InOrderToken) ?? false; if (inOrder) { if (term.Id == Guid.Empty) { throw new ParseException("The InOrder attribute cannot be used when the term ID is empty", xmlNode); } parentInOrderList.Add(term.Id); } // Add the term set to the parent term / term set parentTermContainer.AddTerm(term); var inOrderList = new List <Guid>(); foreach (XElement childNode in xmlNode.Elements()) { switch (childNode.Name.LocalName) { case TaxmlSpec.LocalizedDescriptionToken: int descriptionLcid = this.GetLcidFromLanguageAttribute(childNode, term); term.SetDescription(childNode.Value, descriptionLcid); break; case TaxmlSpec.CustomPropertyToken: this.ProcessCustomProperty(term.CustomProperties, childNode); break; case TaxmlSpec.LocalCustomPropertyToken: this.ProcessCustomProperty(term.LocalCustomProperties, childNode); break; case TaxmlSpec.CustomSortOrderToken: this.ProcessCustomSortOrder(term.CustomSortOrder, childNode); break; case TaxmlSpec.LabelToken: int labelLcid = this.GetLcidFromLanguageAttribute(childNode, term); bool?setAsDefaultLabel = this.GetBooleanAttributeValue(childNode, TaxmlSpec.IsDefaultForLanguageToken); term.AddLabel(childNode.Value, labelLcid, setAsDefaultLabel ?? false); break; case TaxmlSpec.TermToken: this.ProcessTerm(childNode, term, inOrderList, isTermLink: false); break; case TaxmlSpec.TermLinkToken: this.ProcessTerm(childNode, term, inOrderList, isTermLink: true); break; case TaxmlSpec.SyncActionToken: this.ProcessSyncAction(childNode, term); break; default: throw new ParseException("Unimplemented XML tag \"" + childNode.Name.LocalName + "\"", childNode); } } this.ProcessInOrderList(term, inOrderList, xmlNode); }
public CustomOrderedTerm(LocalTerm term, bool writeInOrderAttribute) { this.Term = term; this.WriteInOrderAttribute = writeInOrderAttribute; }
private void ProcessChildTerms(XElement termContainerElement, LocalTermContainer termContainer, List <CustomOrderedTerm> orderedTerms) { LocalTermStore termStore = termContainer.GetTermStore(); foreach (CustomOrderedTerm customOrderedTerm in orderedTerms) { LocalTerm term = customOrderedTerm.Term; bool isTermLink = term.TermKind != LocalTermKind.NormalTerm; XElement termElement; if (isTermLink) { termElement = new XElement(TaxmlSpec.TermLinkToken); if (term.TermKind == LocalTermKind.TermLinkUsingId && term.TermLinkNameHint.Length > 0) { termElement.Add(new XAttribute(TaxmlSpec.NameHintToken, term.TermLinkNameHint)); } } else { termElement = new XElement(TaxmlSpec.TermToken, new XAttribute(TaxmlSpec.NameToken, term.Name)); } termContainerElement.Add(termElement); this.ProcessTaxmlComments(termElement, term); if (term.Id != Guid.Empty) { termElement.Add(new XAttribute(TaxmlSpec.IdToken, term.Id.ToString("B"))); } if (customOrderedTerm.WriteInOrderAttribute) { if (termContainer.CustomSortOrder.Contains(term.Id)) { termElement.Add(new XAttribute(TaxmlSpec.InOrderToken, true)); } } if (!term.IsAvailableForTagging) { termElement.Add(new XAttribute(TaxmlSpec.IsAvailableForTaggingToken, false)); } this.ProcessSyncActionElement(term, termElement); if (isTermLink) { if (!string.IsNullOrWhiteSpace(term.TermLinkSourcePath)) { termElement.Add(new XAttribute(TaxmlSpec.TermLinkSourcePathToken, term.TermLinkSourcePath)); } if (term.IsPinnedRoot) { termElement.Add(new XAttribute(TaxmlSpec.IsPinnedRootToken, true)); } } else { // TODO: If the Term.Owner is the same as the parent object, can we omit it? if (!string.IsNullOrEmpty(term.Owner)) { termElement.Add(new XAttribute(TaxmlSpec.OwnerToken, term.Owner)); } if (term.IsDeprecated) { termElement.Add(new XAttribute(TaxmlSpec.IsDeprecatedToken, true)); } foreach (LocalizedString description in term.Descriptions) { XElement descriptionElement = new XElement(TaxmlSpec.LocalizedDescriptionToken, description); termElement.Add(descriptionElement); if (description.Lcid != term.DefaultLanguageLcid) { descriptionElement.Add(new XAttribute(TaxmlSpec.LanguageToken, description.Lcid)); descriptionElement.Value = description.Value; } } this.ProcessCustomProperties(term.CustomProperties, termElement, isLocal: false); } this.ProcessCustomProperties(term.LocalCustomProperties, termElement, isLocal: true); List <CustomOrderedTerm> orderedChildTerms = this.ProcessCustomSortOrder(term, termElement); if (!isTermLink) { foreach (LocalTermLabel label in term.Labels) { // If this is the Term.Name label, then it doesn't need to be specified explicitly if (label.IsDefault && label.Lcid == term.DefaultLanguageLcid) { continue; } XElement labelElement = new XElement(TaxmlSpec.LabelToken, label.Value); termElement.Add(labelElement); if (label.Lcid != term.DefaultLanguageLcid) { labelElement.Add(new XAttribute(TaxmlSpec.LanguageToken, label.Lcid)); } if (label.IsDefault) { labelElement.Add(new XAttribute(TaxmlSpec.IsDefaultForLanguageToken, true)); } } } this.ProcessChildTerms(termElement, term, orderedChildTerms); } }
private static void ProcessCsvLines(LocalTermGroup termGroup, CsvReader csvReader) { int columnTermSetName = csvReader.GetColumnIndex("Term Set Name"); int columnTermSetDescription = csvReader.GetColumnIndex("Term Set Description"); int columnLcid = csvReader.GetColumnIndex("LCID"); int columnAvailableForTagging = csvReader.GetColumnIndex("Available for Tagging"); int columnTermDescription = csvReader.GetColumnIndex("Term Description"); int[] columnTermLabels = { csvReader.GetColumnIndex("Level 1 Term"), csvReader.GetColumnIndex("Level 2 Term"), csvReader.GetColumnIndex("Level 3 Term"), csvReader.GetColumnIndex("Level 4 Term"), csvReader.GetColumnIndex("Level 5 Term"), csvReader.GetColumnIndex("Level 6 Term"), csvReader.GetColumnIndex("Level 7 Term") }; LocalTermSet termSet = null; while (csvReader.ReadNextLine()) { // Is it a blank row? if (csvReader.Values.All(x => string.IsNullOrWhiteSpace(x))) { // Yes, skip it continue; } string termSetName = csvReader[columnTermSetName].Trim(); string termSetDescription = csvReader[columnTermSetDescription].Trim(); string lcidString = csvReader[columnLcid].Trim(); int currentLcid; if (!int.TryParse(lcidString, out currentLcid)) { currentLcid = termGroup.DefaultLanguageLcid; } bool availableForTagging = true; if (!string.IsNullOrWhiteSpace(csvReader[columnAvailableForTagging])) { availableForTagging = bool.Parse(csvReader[columnAvailableForTagging]); } string termDescription = csvReader[columnTermDescription].Trim(); var termLabels = new List <string>(); for (int i = 0; i < columnTermLabels.Length; ++i) { int columnIndex = columnTermLabels[i]; if (columnIndex < csvReader.Values.Count) { string value = csvReader[columnIndex].Trim(); if (string.IsNullOrEmpty(value)) { break; } termLabels.Add(value); } } if (!string.IsNullOrEmpty(termSetName)) { termSet = termGroup.AddTermSet(Guid.Empty, termSetName); termSet.SetName(termSetName, currentLcid); termSet.Description = termSetDescription; } if (termSet != null) { LocalTermContainer parent = termSet; if (termLabels.Count == 0) { throw new Exception("Missing term label"); } foreach (string parentTermLabel in termLabels.Take(termLabels.Count - 1)) { LocalTerm newParent; if (!parent.Terms.TryGetByName(parentTermLabel, currentLcid, out newParent)) { throw new Exception("No match found for parent term \"" + parentTermLabel + "\""); } parent = newParent; } string termLabel = termLabels.Last(); LocalTerm term = parent.AddTerm(Guid.Empty, termLabel); term.SetName(termLabel, currentLcid); term.SetDescription(termDescription, currentLcid); term.IsAvailableForTagging = availableForTagging; } } }