/// <inheritdoc /> public override IEnumerable <T> Execute(string query) { var navigator = _node.GetNavigator(); var nodes = navigator.Select(query); var htmlElements = (from IXPathNavigable node in nodes select _page.ElementFactory.Create <T>(_page, node)).ToList(); var radioButtonNames = new List <string>(); // Radio buttons are expressed as multiple HTML tags, but need to be returned as a single HtmlRadioButton instance // The factory above has already created multiple instances based on the multiple nodes found // so we now need to find any radio buttons and filter out the duplicates // This is a little inefficient because there is the overhead of creating and initializing the radio button // multiple times however this code is much cleaner foreach (var element in htmlElements) { var radioButton = element as HtmlRadioButton; if (radioButton == null) { // Not a radio button so no filtering is required yield return(element); } else if (radioButtonNames.Contains(radioButton.Name) == false) { radioButtonNames.Add(radioButton.Name); yield return(element); } } }
/// <summary> /// Determines whether the specified navigable has the specified attribute. /// </summary> /// <param name="navigable"> /// The navigable. /// </param> /// <param name="name"> /// The name. /// </param> /// <returns> /// <c>true</c> if the specified navigable has the attribute; otherwise, <c>false</c>. /// </returns> public static bool HasAttribute(this IXPathNavigable navigable, string name) { var navigator = navigable.GetNavigator(); var checkedFound = navigator.MoveToAttribute(name, string.Empty); return(checkedFound); }
/// <summary> /// Builds the supported tags message. /// </summary> /// <param name="node"> /// The node. /// </param> /// <param name="tags"> /// The tags. /// </param> /// <returns> /// A <see cref="string"/> value. /// </returns> private static string BuildSupportedTagsMessage(IXPathNavigable node, IEnumerable <SupportedTagAttribute> tags) { var supportedTags = tags.Select(x => x.ToString()).Aggregate((i, j) => i + Environment.NewLine + j); var navigator = node.GetNavigator(); var message = string.Format( CultureInfo.CurrentCulture, "The specified '{0}' element is invalid. The supported tags for this node are: {1}", navigator.Name, supportedTags); return(message); }
/// <summary> /// Sets the selected. /// </summary> /// <param name="navigable"> /// The navigable. /// </param> /// <param name="value"> /// if set to <c>true</c> [value]. /// </param> public static void SetSelected(this IXPathNavigable navigable, bool value) { var navigator = navigable.GetNavigator(); var hasAttribute = navigator.MoveToAttribute("selected", string.Empty); if (hasAttribute == value) { // No change is required return; } if (value) { // Set the attribute navigator.SetAttribute(string.Empty, "selected", string.Empty, "selected"); } else { // Remove the checked attribute if it exists navigator.DeleteSelf(); } }
public static Type FindBestMatchingType(this Type elementType, IXPathNavigable node) { if (elementType == null) { throw new ArgumentNullException("elementType"); } if (node == null) { throw new ArgumentNullException("node"); } var navigator = node.GetNavigator(); var possibleTypes = GetMatchingTypes(elementType).ToList(); var matchingTypes = new List<Type>(); // The node name should already be folded to lower case when the HTML was read var nodeName = navigator.Name; foreach (var possibleType in possibleTypes) { var attributes = possibleType.GetCustomAttributes(typeof(SupportedTagAttribute), true) .OfType<SupportedTagAttribute>(); foreach (var attribute in attributes) { if (nodeName.Equals(attribute.TagName, StringComparison.OrdinalIgnoreCase) == false) { continue; } if (attribute.HasAttributeFilter) { // The attribute name should already be folded to lower case when the HTML was read var queryAttributeName = attribute.AttributeName.ToLowerInvariant(); var matchingAttribute = navigator.GetAttribute(queryAttributeName, string.Empty); if (matchingAttribute.Equals(attribute.AttributeValue, StringComparison.OrdinalIgnoreCase)) { matchingTypes.Add(possibleType); } } else { matchingTypes.Add(possibleType); } } } if (matchingTypes.Count == 0) { return typeof(AnyHtmlElement); } if (matchingTypes.Count > 1) { var matchingTypeNames = matchingTypes.Aggregate(string.Empty, (x, y) => x + Environment.NewLine + y); var message = string.Format( CultureInfo.CurrentCulture, Resources.TypeExtensions_MultipleTypeMatchesForNode, elementType.FullName, navigator.OuterXml, matchingTypeNames); throw new InvalidHtmlElementMatchException(message); } return matchingTypes[0]; }
public static Type FindBestMatchingType(this Type elementType, IXPathNavigable node) { if (elementType == null) { throw new ArgumentNullException("elementType"); } if (node == null) { throw new ArgumentNullException("node"); } var navigator = node.GetNavigator(); var possibleTypes = GetMatchingTypes(elementType).ToList(); var matchingTypes = new List <Type>(); // The node name should already be folded to lower case when the HTML was read var nodeName = navigator.Name; foreach (var possibleType in possibleTypes) { var attributes = possibleType.GetCustomAttributes(typeof(SupportedTagAttribute), true) .OfType <SupportedTagAttribute>(); foreach (var attribute in attributes) { if (nodeName.Equals(attribute.TagName, StringComparison.OrdinalIgnoreCase) == false) { continue; } if (attribute.HasAttributeFilter) { // The attribute name should already be folded to lower case when the HTML was read var queryAttributeName = attribute.AttributeName.ToLowerInvariant(); var matchingAttribute = navigator.GetAttribute(queryAttributeName, string.Empty); if (matchingAttribute.Equals(attribute.AttributeValue, StringComparison.OrdinalIgnoreCase)) { matchingTypes.Add(possibleType); } } else { matchingTypes.Add(possibleType); } } } if (matchingTypes.Count == 0) { return(typeof(AnyHtmlElement)); } if (matchingTypes.Count > 1) { var matchingTypeNames = matchingTypes.Aggregate(string.Empty, (x, y) => x + Environment.NewLine + y); var message = string.Format( CultureInfo.CurrentCulture, Resources.TypeExtensions_MultipleTypeMatchesForNode, elementType.FullName, navigator.OuterXml, matchingTypeNames); throw new InvalidHtmlElementMatchException(message); } return(matchingTypes[0]); }
/// <summary> /// Builds the supported tags message. /// </summary> /// <param name="node"> /// The node. /// </param> /// <param name="tags"> /// The tags. /// </param> /// <returns> /// A <see cref="string"/> value. /// </returns> private static string BuildSupportedTagsMessage(IXPathNavigable node, IEnumerable<SupportedTagAttribute> tags) { var supportedTags = tags.Select(x => x.ToString()).Aggregate((i, j) => i + Environment.NewLine + j); var navigator = node.GetNavigator(); var message = string.Format( CultureInfo.CurrentCulture, "The specified '{0}' element is invalid. The supported tags for this node are: {1}", navigator.Name, supportedTags); return message; }