/// <summary>
        /// Gets a specific ESD metadata term
        /// </summary>
        /// <param name="termId">The id of the term to get</param>
        /// <param name="preferredState">Specify whether the term must be preferred or non-preferred (for SKOS-compatible XML after published after June 2010, only preferred is relevant)</param>
        /// <returns>The relevant term, or null if not found</returns>
        public EsdTerm GetTerm(string termId, EsdPreferredState preferredState)
        {
            string xPath = String.Empty;

            switch (preferredState)
            {
            case EsdPreferredState.Preferred:
                xPath = this.skosCompatible ? "ns:Item[@Id=\"{0}\"]" : "ns:Item[@Preferred='true' and @Id=\"{0}\"]";
                break;

            case EsdPreferredState.NonPreferred:
                if (this.skosCompatible)
                {
                    return(null);                         // non-preferred terms no longer have their own id
                }
                xPath = "ns:Item[@Preferred='false' and @Id=\"{0}\"]";
                break;

            case EsdPreferredState.Any:     // for SKOS-compatible this effectively is the same as EsdPreferredState.Preferred
                xPath = "ns:Item[@Id=\"{0}\"]";
                break;
            }
            xPath = String.Format(CultureInfo.InvariantCulture, xPath, termId.Trim());
            XPathNodeIterator it = this.SelectNodes(xPath);

            if (it.Count != 1)
            {
                return(null);
            }

            it.MoveNext();
            return(this.GetEsdTermFromXml(it.Current));
        }
        /// <summary>
        /// Gets ESD metadata terms based on the name of the term
        /// </summary>
        /// <param name="termName">The term name to search for</param>
        /// <param name="exactMatch">true to match the whole name of a term; false to match any part of the term</param>
        /// <param name="preferredState">Specify whether the term must be preferred or non-preferred</param>
        /// <returns>A collection of matching terms</returns>
        /// <remarks>Matching is not case-sensitive. For SKOS-compatible lists (those published after June 2010) the behaviour
        /// of this method has changed. When a search matches a non-preferred term it used to return the non-preferred term
        /// as a top-level object alongside preferred terms. For SKOS compatible lists it now returns the preferred term which
        /// goes with the non-preferred term.</remarks>
        public EsdTermCollection GetTerms(string termName, bool exactMatch, EsdPreferredState preferredState)
        {
            // double-quotes (") are used to delimit xpath strings in this method because it allows apostrophes in the string

            string xPath = null;

            if (exactMatch)
            {
                switch (preferredState)
                {
                case EsdPreferredState.Preferred:
                    xPath = this.skosCompatible ? "ns:Item[ns:Name[translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=\"{0}\"]]"
                            : "ns:Item[@Preferred='true' and ns:Name[translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=\"{0}\"]]";
                    break;

                case EsdPreferredState.NonPreferred:
                    xPath = this.skosCompatible ? "ns:Item[ns:AlternativeName[translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=\"{0}\"]]"
                    : "ns:Item[@Preferred='false' and ns:Name[translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=\"{0}\"]]";
                    break;

                case EsdPreferredState.Any:
                    xPath = this.skosCompatible ? "ns:Item[ns:Name[translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=\"{0}\"] or ns:AlternativeName[translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=\"{0}\"]]"
                            : "ns:Item[ns:Name[translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=\"{0}\"]]";
                    break;
                }
            }
            else
            {
                switch (preferredState)
                {
                case EsdPreferredState.Preferred:
                    xPath = this.skosCompatible ? "ns:Item[ns:Name[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), \"{0}\")]]"
                            : "ns:Item[@Preferred='true' and ns:Name[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), \"{0}\")]]";
                    break;

                case EsdPreferredState.NonPreferred:
                    xPath = this.skosCompatible ? "ns:Item[ns:AlternativeName[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), \"{0}\")]]"
                            : "ns:Item[@Preferred='false' and ns:Name[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), \"{0}\")]]";
                    break;

                case EsdPreferredState.Any:
                    xPath = this.skosCompatible ? "ns:Item[ns:Name[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), \"{0}\")] or ns:AlternativeName[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), \"{0}\")]]"
                            : "ns:Item[ns:Name[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), \"{0}\")]]";
                    break;
                }
            }
            XPathNodeIterator it = this.SelectNodes(String.Format(CultureInfo.InvariantCulture, xPath, termName.Trim().ToLower(CultureInfo.CurrentCulture)));

            EsdTermCollection terms = new EsdTermCollection();

            while (it.MoveNext())
            {
                terms.Add(this.GetEsdTermFromXml(it.Current));
            }

            terms.Sort();
            return(terms);
        }
示例#3
0
 /// <summary>
 /// Gets the numeric index of a term's position in the collection
 /// </summary>
 /// <param name="termName">Name of the term.</param>
 /// <param name="state">The state.</param>
 /// <returns></returns>
 public int IndexOf(string termName, EsdPreferredState state)
 {
     foreach (EsdTerm term in this)
     {
         if (term.Text.ToLowerInvariant() == termName.ToLowerInvariant() &&
             (state == EsdPreferredState.Any || ((state == EsdPreferredState.Preferred) == term.Preferred)))
         {
             return(IndexOf(term));
         }
     }
     return(-1);
 }
示例#4
0
 /// <summary>
 /// Gets the numeric index of a term's position in the collection
 /// </summary>
 /// <param name="termId">The term id.</param>
 /// <param name="state">The state.</param>
 /// <returns></returns>
 public int IndexOfId(string termId, EsdPreferredState state)
 {
     foreach (EsdTerm term in this)
     {
         if (term.Id == termId &&
             (state == EsdPreferredState.Any || ((state == EsdPreferredState.Preferred) == term.Preferred)))
         {
             return(IndexOf(term));
         }
     }
     return(-1);
 }
示例#5
0
        /// <summary>
        /// Checks the terms in the control against the specified controlled list
        /// </summary>
        /// <returns>true if all terms are valid; false if any one term is not valid (matching is not case sensitive)</returns>
        protected override bool EvaluateIsValid()
        {
            // If an instance of this validator is run more than once on one request, just return the same result and don't do all the work again.
            // Not that anyone would run it more than once on one request, unless it was really inefficient (SharePoint field controls).
            if (cachedIsValid != null)
            {
                return((bool)cachedIsValid);
            }

            // check the list was specified
            if (this.controlledListName == null || this.controlledListName.Length == 0)
            {
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "The ControlledListName property was not set for {0}", this.GetType().ToString()));
            }

            // get control to validate and get its value
            Control controlToValidate = this.Parent.FindControl(this.ControlToValidate);

            string valueToValidate = String.Empty;

            // If it's a textbox ensure it's in a variable we can use later to put a tidied-up value back into the textbox
            TextBox textboxToValidate = controlToValidate as TextBox;

            if (textboxToValidate != null)
            {
                // Trim off any trailing semi-colon separator
                valueToValidate = textboxToValidate.Text.TrimEnd(' ', ';');
            }
            else
            {
                // Maybe it's a list of some kind? Test with cast rather than .GetType() == typeof(ListControl)
                // because need to support customised derived types of control.
                ListControl listToValidate = controlToValidate as ListControl;
                if (listToValidate != null)
                {
                    EsdTermCollection selectedTerms = new EsdTermCollection();
                    foreach (ListItem item in listToValidate.Items)
                    {
                        if (item.Selected)
                        {
                            EsdTerm selectedTerm = new EsdTerm();
                            selectedTerm.Id   = item.Value;
                            selectedTerm.Text = item.Text;
                            selectedTerms.Add(selectedTerm);
                        }
                    }
                    valueToValidate = selectedTerms.ToString();
                }
                else
                {
                    // No other control type supported yet - throw a useful error for the developer
                    throw new ArgumentException(String.Format("The control type matched by the ControlToValidate property, {0}, is not supported by the EsdTermValidator", controlToValidate.GetType().ToString()));
                }
            }


            // this isn't a required validator
            if (valueToValidate.Length == 0)
            {
                this.cachedIsValid = true;
                return(true);
            }

            // get the XML we need
            EsdControlledList esdListXml = EsdControlledList.GetControlledList(this.controlledListName, false);

            // box has semi-colon separated list of preferred terms
            string[] searchTerms;
            if (this.multipleTerms)
            {
                valueToValidate = valueToValidate.Trim(' ', ';');
                searchTerms     = valueToValidate.Split(';');
            }
            else
            {
                searchTerms    = new string[1];
                searchTerms[0] = valueToValidate.Trim();
            }

            // If we only want preferred terms, search for any term then we can convert it to the preferred term
            EsdPreferredState searchState = (this.preferredState == EsdPreferredState.Preferred ? EsdPreferredState.Any : this.preferredState);

            // Search for terms and gather results
            StringBuilder termBuilder = new StringBuilder();

            this.invalidTerms = new ArrayList();
            this.matchedTerms.Clear();
            List <string> matchedTermIds    = new List <string>();
            int           totalMatchedTerms = 0;
            string        trimmedSearch;
            Regex         numeric = new Regex("^[0-9]+$");

            foreach (string searchTerm in searchTerms)
            {
                trimmedSearch = searchTerm.Trim();
                if (trimmedSearch.Length == 0)
                {
                    continue;
                }

                if (this.termIdsAllowed && numeric.IsMatch(trimmedSearch))
                {
                    if (this.allowedTerms.Count > 0)
                    {
                        // Validate the text of the term against just those terms in the AllowedTerms collection
                        int termIndex = this.allowedTerms.IndexOfId(trimmedSearch, this.preferredState);

                        // If that didn't work and we want preferred terms, see if it matches a non-preferred term and the preferred term is allowed
                        if (this.preferredState == EsdPreferredState.Preferred && termIndex == -1)
                        {
                            EsdTerm matchedTerm = esdListXml.GetTerm(trimmedSearch, EsdPreferredState.NonPreferred);
                            if (matchedTerm != null)
                            {
                                matchedTerm = esdListXml.GetPreferredTerm(matchedTerm.ConceptId);
                                if (matchedTerm != null)
                                {
                                    termIndex = this.allowedTerms.IndexOf(matchedTerm.Text, EsdPreferredState.Preferred);
                                }
                            }
                        }

                        if (termIndex > -1)
                        {
                            EsdTerm matchedTerm = this.allowedTerms[termIndex];
                            totalMatchedTerms++;

                            // Add it unless it's a duplicate
                            if (!matchedTermIds.Contains(matchedTerm.Id))
                            {
                                this.matchedTerms.Add(matchedTerm);

                                if (termBuilder.Length > 0)
                                {
                                    termBuilder.Append("; ");
                                }
                                termBuilder.Append(matchedTerm.Id);

                                matchedTermIds.Add(matchedTerm.Id);
                            }
                        }
                        else
                        {
                            this.invalidTerms.Add(trimmedSearch);

                            if (termBuilder.Length > 0)
                            {
                                termBuilder.Append("; ");
                            }
                            termBuilder.Append(trimmedSearch);
                        }
                    }
                    else
                    {
                        EsdTerm matchedTerm = esdListXml.GetTerm(trimmedSearch, searchState);
                        if (matchedTerm != null)
                        {
                            totalMatchedTerms++;

                            // If we want preferred terms, ensure we have the preferred term
                            if (this.preferredState == EsdPreferredState.Preferred && !matchedTerm.Preferred)
                            {
                                matchedTerm = esdListXml.GetPreferredTerm(matchedTerm.ConceptId);
                            }

                            // Add it unless it's a duplicate
                            if (!matchedTermIds.Contains(matchedTerm.Id))
                            {
                                this.matchedTerms.Add(matchedTerm);

                                if (termBuilder.Length > 0)
                                {
                                    termBuilder.Append("; ");
                                }
                                termBuilder.Append(matchedTerm.Id);

                                matchedTermIds.Add(matchedTerm.Id);
                            }
                        }
                        else
                        {
                            this.invalidTerms.Add(trimmedSearch);

                            if (termBuilder.Length > 0)
                            {
                                termBuilder.Append("; ");
                            }
                            termBuilder.Append(trimmedSearch);
                        }
                    }
                }
                else
                {
                    if (this.allowedTerms.Count > 0)
                    {
                        // Validate the text of the term against just those terms in the AllowedTerms collection
                        int termIndex = this.allowedTerms.IndexOf(trimmedSearch, this.preferredState);

                        // If that didn't work and we want preferred terms, see if it matches a non-preferred term and the preferred term is allowed
                        if (this.preferredState == EsdPreferredState.Preferred && termIndex == -1)
                        {
                            EsdTermCollection matchedTerms = esdListXml.GetTerms(trimmedSearch, true, EsdPreferredState.NonPreferred);
                            if (matchedTerms.Count == 1)
                            {
                                EsdTerm matchedTerm = esdListXml.GetPreferredTerm(matchedTerms[0].ConceptId);
                                if (matchedTerm != null)
                                {
                                    termIndex = this.allowedTerms.IndexOf(matchedTerm.Text, EsdPreferredState.Preferred);
                                }
                            }
                        }

                        if (termIndex > -1)
                        {
                            EsdTerm matchedTerm = this.allowedTerms[termIndex];
                            totalMatchedTerms++;

                            // Add it unless it's a duplicate
                            if (!matchedTermIds.Contains(matchedTerm.Id))
                            {
                                this.matchedTerms.Add(matchedTerm);

                                if (termBuilder.Length > 0)
                                {
                                    termBuilder.Append("; ");
                                }
                                termBuilder.Append(matchedTerm.Text);

                                matchedTermIds.Add(matchedTerm.Id);
                            }
                        }
                        else
                        {
                            this.invalidTerms.Add(trimmedSearch);

                            if (termBuilder.Length > 0)
                            {
                                termBuilder.Append("; ");
                            }
                            termBuilder.Append(trimmedSearch);
                        }
                    }
                    else
                    {
                        // Validate the text of the term against the full controlled list
                        EsdTermCollection terms = esdListXml.GetTerms(trimmedSearch, true, searchState);

                        if (terms.Count == 1)
                        {
                            totalMatchedTerms++;

                            // If we want preferred terms, ensure we have the preferred term
                            EsdTerm matchedTerm = terms[0];
                            if (this.preferredState == EsdPreferredState.Preferred && !matchedTerm.Preferred)
                            {
                                matchedTerm = esdListXml.GetPreferredTerm(matchedTerm.ConceptId);
                            }

                            // Add it unless it's a duplicate
                            if (!matchedTermIds.Contains(matchedTerm.Id))
                            {
                                this.matchedTerms.Add(matchedTerm);

                                if (termBuilder.Length > 0)
                                {
                                    termBuilder.Append("; ");
                                }
                                termBuilder.Append(matchedTerm.Text);

                                matchedTermIds.Add(matchedTerm.Id);
                            }
                        }
                        else
                        {
                            this.invalidTerms.Add(trimmedSearch);

                            if (termBuilder.Length > 0)
                            {
                                termBuilder.Append("; ");
                            }
                            termBuilder.Append(trimmedSearch);
                        }
                    }
                }
            }

            // if control had user-editable (rather than selectable) values, update control with case-corrected terms
            if (textboxToValidate != null)
            {
                textboxToValidate.Text = termBuilder.ToString();
            }

            // return true if terms valid; false if any one term is not valid
            // totalMatchedTerms may not be the same as this.MatchedTerms.Count because totalMatchedTerms is incremented for a duplicate
            if (totalMatchedTerms == searchTerms.Length)
            {
                this.cachedIsValid = true;
                return(true); // all terms were matched
            }
            else
            {
                StringBuilder errorBuilder  = new StringBuilder();
                string        listName      = esdListXml.AbbreviatedName;
                string        termDelimiter = "'";

                // build error message with singular grammar
                if (this.invalidTerms.Count == 1)
                {
                    if (this.allowedTerms.Count > 0)
                    {
                        errorBuilder.Append(termDelimiter).Append(this.invalidTerms[0]).Append(termDelimiter).Append(" is not one of the ").Append(listName).Append(" terms allowed here");
                    }
                    else
                    {
                        errorBuilder.Append(termDelimiter).Append(this.invalidTerms[0]).Append(termDelimiter).Append(" is not a");
                        if (listName.StartsWith("A") || listName.StartsWith("E") || listName.StartsWith("I") || listName.StartsWith("O") || listName.StartsWith("U"))
                        {
                            errorBuilder.Append("n");
                        }
                        errorBuilder.Append(" ").Append(listName).Append(" ");
                        if (this.preferredState == EsdPreferredState.Preferred)
                        {
                            errorBuilder.Append("preferred");
                        }
                        else if (this.preferredState == EsdPreferredState.NonPreferred)
                        {
                            errorBuilder.Append("non-preferred");
                        }
                        errorBuilder.Append(" term");
                    }
                }
                else
                {
                    // build error message with plural grammar
                    for (short i = 0; i < this.invalidTerms.Count; i++)
                    {
                        if (errorBuilder.Length > 0)
                        {
                            if (i == (this.invalidTerms.Count - 1))
                            {
                                errorBuilder.Append(" and ");
                            }
                            else
                            {
                                errorBuilder.Append(", ");
                            }
                        }
                        errorBuilder.Append(termDelimiter).Append(this.invalidTerms[i]).Append(termDelimiter);
                    }

                    if (this.allowedTerms.Count > 0)
                    {
                        errorBuilder.Append(" are not among the ").Append(listName).Append(" terms allowed here");
                    }
                    else
                    {
                        errorBuilder.Append(" are not ").Append(listName).Append(" ");
                        if (this.preferredState == EsdPreferredState.Preferred)
                        {
                            errorBuilder.Append("preferred");
                        }
                        else if (this.preferredState == EsdPreferredState.NonPreferred)
                        {
                            errorBuilder.Append("non-preferred");
                        }
                        errorBuilder.Append(" terms");
                    }
                }

                this.ErrorMessage = errorBuilder.ToString();

                this.cachedIsValid = false;
                return(false);
            }
        }