//---------------------------------------------------------------------------------------------------------------------
 /// <summary>Creates an instance of an OpenSearchParameterDefinition.</summary>
 /// <param name="name">The query string name of the parameter, e.g. "bbox".</param>
 /// <param name="identifier">The fully qualified identifier of the parameter, e.g. "geo:box".</param>
 /// <param name="identifierNamespaceUri">The namespace URI part of the fully qualified identifier of the parameter, e.g. "http://a9.com/-/opensearch/extensions/geo/1.0/".</param>
 /// <param name="identifierLocalName">The local name part of the fully qualified identifier of the parameter, e.g. "box".</param>
 /// <param name="parameter">An optional reference to the OpenSearch Parameter extension object that contains further information about the parameter, such as options for values.</param>
 public OpenSearchParameterDefinition(string name, string identifier, string identifierNamespaceUri, string identifierLocalName, OpenSearchDescriptionUrlParameter parameter)
 {
     this.Name = name;
     this.Identifier = identifier;
     if (identifierNamespaceUri != null && identifierLocalName != null) {
         this.IdentifierNamespaceUri = identifierNamespaceUri;
         this.IdentifierLocalName = identifierLocalName;
     }
     this.Parameter = parameter;
 }
        //---------------------------------------------------------------------------------------------------------------------
        /// <summary>Creates an OpenSearchParameterValueSet instance based on the specified OpenSearch template and optional additional parameter information.</summary>
        /// <returns>A new OpenSearchParameterValueSet instance.</returns>
        /// <param name="template">An OpenSearch template URL.</param>
        /// <param name="origParams">An array of objects containing parameter information as defined by the OpenSearch Parameter extension.</returns>
        public static OpenSearchParameterValueSet FromOpenSearchDescription(string template, OpenSearchDescriptionUrlParameter[] origParams = null, XmlSerializerNamespaces namespaces = null)
        {
            OpenSearchParameterValueSet result = new OpenSearchParameterValueSet();

            Dictionary<string, OpenSearchDescriptionUrlParameter> tempParameters = new Dictionary<string, OpenSearchDescriptionUrlParameter>();
            Dictionary<string, string> tempNamespaces = null;
            if (origParams != null) {
                foreach (OpenSearchDescriptionUrlParameter origParam in origParams) tempParameters.Add(origParam.Name, origParam);
            }

            if (namespaces != null) {
                result.nameTable = new NameTable();
                tempNamespaces = new Dictionary<string, string>();
                foreach (XmlQualifiedName qn in namespaces.ToArray()) {
                    tempNamespaces.Add(qn.Name, result.nameTable.Add(qn.Namespace));
                }
            }

            // Make sure URL is valid
            Match match = urlRegex.Match(template);
            if (!match.Success) throw new OpenSearchException(String.Format("Invalid URL template: {0}", template));

            // Split by query string parameter and add parameter definitions to the internal dictionaries:
            // parameters can be settable (e.g. name={key}, name={prefix:key}) or fixed (name=value)
            string[] items = match.Groups[1].Value.Split('&');
            foreach (string item in items) {
                Match match2 = parameterDefinitionRegex.Match(item);
                if (!match2.Success) continue;
                string name = match2.Groups[1].Value;
                OpenSearchParameterDefinition paramDef;
                if (match2.Groups[3].Success) { // parameter is settable
                    string identifier = match2.Groups[3].Value;
                    string identifierNamespaceUri = null, identifierLocalName = null;
                    if (tempNamespaces != null) {
                        string[] parts = identifier.Split(':');
                        if (parts.Length == 2) {
                            identifierNamespaceUri = tempNamespaces.ContainsKey(parts[0]) ? tempNamespaces[parts[0]] : null;
                            if (identifierNamespaceUri != null) identifierLocalName = parts[1];
                        }
                    }
                    paramDef = new OpenSearchParameterDefinition(name, identifier, identifierNamespaceUri, identifierLocalName, tempParameters.ContainsKey(name) ? tempParameters[name] : null);
                    result.parametersByIdentifier[identifier] = paramDef;
                } else { // parameter is fixed
                    paramDef = new OpenSearchParameterDefinition(name);
                    result.values[paramDef] = new string[] {match2.Groups[2].Value};
                }
                result.parametersByName[paramDef.Name] = paramDef;
            }

            return result;
        }