Skip to content

Commit

Permalink
Merge pull request #509 from rwecho/master
Browse files Browse the repository at this point in the history
Set inner html as default to implict set ReturnType
  • Loading branch information
JonathanMagnan authored Aug 1, 2023
2 parents e581d69 + 6fae66d commit 3999898
Show file tree
Hide file tree
Showing 5 changed files with 606 additions and 47 deletions.
134 changes: 89 additions & 45 deletions src/HtmlAgilityPack.Shared/HtmlNode.Encapsulator.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators.
// Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators.
// Website & Documentation: http://html-agility-pack.net
// Forum & Issues: https://github.com/zzzprojects/html-agility-pack
// License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE
// More projects: http://www.zzzprojects.com/
// Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved.
// Copyright ZZZ Projects Inc. 2014 - 2017. All rights reserved.

#if !METRO && !NETSTANDARD1_3

Expand All @@ -24,13 +24,14 @@ public partial class HtmlNode
/// <returns>Returns an object of type T including Encapsulated data.</returns>
/// <exception cref="ArgumentException">Why it's thrown.</exception>
/// <exception cref="ArgumentNullException">Why it's thrown.</exception>
/// <exception cref="MissingMethodException">Why it's thrown.</exception>
/// <exception cref="MissingXPathException">Why it's thrown.</exception>
/// <exception cref="XPathException">Why it's thrown.</exception>
/// <exception cref="NodeNotFoundException">Why it's thrown.</exception>
/// <exception cref="NodeAttributeNotFoundException">Why it's thrown.</exception>
/// <exception cref="FormatException">Why it's thrown.</exception>
/// <exception cref="MissingMethodException"><see cref="MissingMethodException"/></exception>
/// <exception cref="MissingXPathException"><see cref="MissingXPathException"/></exception>
/// <exception cref="XPathException"><see cref="XPathExeption"/></exception>
/// <exception cref="NodeNotFoundException"><see cref="NodeNotFoundException"/></exception>
/// <exception cref="NodeAttributeNotFoundException"><see cref="NodeAttributeNotFoundException"/></exception>
/// <exception cref="FormatException">Why it's thrown.</exception>
/// <exception cref="Exception">Why it's thrown.</exception>
/// <exception cref="InvalidNodeReturnTypeException"><see cref="InvalidNodeReturnTypeException"/></exception>
public T GetEncapsulatedData<T>()
{
return (T)GetEncapsulatedData(typeof(T), null);
Expand All @@ -45,13 +46,14 @@ public T GetEncapsulatedData<T>()
/// <returns>Returns an object of type T including Encapsulated data.</returns>
/// <exception cref="ArgumentException">Why it's thrown.</exception>
/// <exception cref="ArgumentNullException">Why it's thrown.</exception>
/// <exception cref="MissingMethodException">Why it's thrown.</exception>
/// <exception cref="MissingXPathException">Why it's thrown.</exception>
/// <exception cref="XPathException">Why it's thrown.</exception>
/// <exception cref="NodeNotFoundException">Why it's thrown.</exception>
/// <exception cref="NodeAttributeNotFoundException">Why it's thrown.</exception>
/// <exception cref="FormatException">Why it's thrown.</exception>
/// <exception cref="MissingMethodException"><see cref="MissingMethodException"/></exception>
/// <exception cref="MissingXPathException"><see cref="MissingXPathException"/></exception>
/// <exception cref="XPathException"><see cref="XPathExeption"/></exception>
/// <exception cref="NodeNotFoundException"><see cref="NodeNotFoundException"/></exception>
/// <exception cref="NodeAttributeNotFoundException"><see cref="NodeAttributeNotFoundException"/></exception>
/// <exception cref="FormatException">Why it's thrown.</exception>
/// <exception cref="Exception">Why it's thrown.</exception>
/// <exception cref="InvalidNodeReturnTypeException"><see cref="InvalidNodeReturnTypeException"/></exception>
public T GetEncapsulatedData<T>(HtmlDocument htmlDocument)
{
return (T)GetEncapsulatedData(typeof(T), htmlDocument);
Expand All @@ -67,13 +69,14 @@ public T GetEncapsulatedData<T>(HtmlDocument htmlDocument)
/// <returns>Returns an object of type targetType including Encapsulated data.</returns>
/// <exception cref="ArgumentException">Why it's thrown.</exception>
/// <exception cref="ArgumentNullException">Why it's thrown.</exception>
/// <exception cref="MissingMethodException">Why it's thrown.</exception>
/// <exception cref="MissingXPathException">Why it's thrown.</exception>
/// <exception cref="XPathException">Why it's thrown.</exception>
/// <exception cref="NodeNotFoundException">Why it's thrown.</exception>
/// <exception cref="NodeAttributeNotFoundException">Why it's thrown.</exception>
/// <exception cref="FormatException">Why it's thrown.</exception>
/// <exception cref="MissingMethodException"><see cref="MissingMethodException"/></exception>
/// <exception cref="MissingXPathException"><see cref="MissingXPathException"/></exception>
/// <exception cref="XPathException"><see cref="XPathExeption"/></exception>
/// <exception cref="NodeNotFoundException"><see cref="NodeNotFoundException"/></exception>
/// <exception cref="NodeAttributeNotFoundException"><see cref="NodeAttributeNotFoundException"/></exception>
/// <exception cref="FormatException">Why it's thrown.</exception>
/// <exception cref="Exception">Why it's thrown.</exception>
/// <exception cref="InvalidNodeReturnTypeException"><see cref="InvalidNodeReturnTypeException"/></exception>
public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = null)
{

Expand Down Expand Up @@ -175,9 +178,11 @@ public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = n
// Property is None-IEnumerable HasXPath-user-defined class
if (propertyInfo.PropertyType.IsDefinedAttribute(typeof(HasXPathAttribute)) == true)
{
HtmlDocument innerHtmlDocument = new HtmlDocument();
HtmlDocument innerHtmlDocument = new HtmlDocument();

innerHtmlDocument.LoadHtml(Tools.GetHtmlForEncapsulation(htmlNode, xPathAttribute.NodeReturnType));
innerHtmlDocument.LoadHtml(Tools.GetHtmlForEncapsulation(
htmlNode,
xPathAttribute.IsNodeReturnTypeExplicitlySet ? xPathAttribute.NodeReturnType : ReturnType.InnerHtml));

object o = GetEncapsulatedData(propertyInfo.PropertyType, innerHtmlDocument);

Expand All @@ -192,12 +197,13 @@ public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = n
{
string result = string.Empty;

if (xPathAttribute.AttributeName == null) // It target value of HTMLTag
if (xPathAttribute.AttributeName == null) // It target value of HTMLTag
{
result = Tools.GetNodeValueBasedOnXPathReturnType<string>(htmlNode, xPathAttribute);
}
else // It target attribute of HTMLTag
{
ThrowIfNodeReturnTypeIsExplicitlySetWhenAttributeNameIsGiven(xPathAttribute);
result = htmlNode.GetAttributeValue(xPathAttribute.AttributeName, null);
}

Expand Down Expand Up @@ -295,7 +301,9 @@ public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = n
foreach (HtmlNode node in nodeCollection)
{
HtmlDocument innerHtmlDocument = new HtmlDocument();
innerHtmlDocument.LoadHtml(Tools.GetHtmlForEncapsulation(node, xPathAttribute.NodeReturnType));
innerHtmlDocument.LoadHtml(Tools.GetHtmlForEncapsulation(
node,
xPathAttribute.IsNodeReturnTypeExplicitlySet ? xPathAttribute.NodeReturnType : ReturnType.InnerHtml));

object o = GetEncapsulatedData(T_Types[0], innerHtmlDocument);

Expand Down Expand Up @@ -324,6 +332,8 @@ public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = n
}
else // It target attribute
{
ThrowIfNodeReturnTypeIsExplicitlySetWhenAttributeNameIsGiven(xPathAttribute);

foreach (HtmlNode node in nodeCollection)
{
string nodeAttributeValue = node.GetAttributeValue(xPathAttribute.AttributeName, null);
Expand Down Expand Up @@ -383,7 +393,13 @@ public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = n
}



private static void ThrowIfNodeReturnTypeIsExplicitlySetWhenAttributeNameIsGiven(XPathAttribute xPathAttr)
{
if (xPathAttr.IsNodeReturnTypeExplicitlySet && !string.IsNullOrEmpty(xPathAttr.AttributeName))
{
throw new InvalidNodeReturnTypeException("Specifying a ReturnType value not allowed for XPathAttribute annotations targeting element attributes");
}
}
}


Expand Down Expand Up @@ -627,12 +643,10 @@ internal static IList GetNodesValuesBasedOnXPathReturnType(HtmlNodeCollection ht


IList result = listGenericType.CreateIListOfType();

foreach (HtmlNode node in htmlNodeCollection)
{
result.Add(Convert.ChangeType(GetHtmlForEncapsulation(node, xPathAttribute.NodeReturnType), listGenericType));
result.Add(Convert.ChangeType(GetHtmlForEncapsulation(node, xPathAttribute.NodeReturnType), listGenericType));
}

return result;
}

Expand Down Expand Up @@ -729,7 +743,7 @@ internal static int CountOfIEnumerable<T>(this IEnumerable<T> source)
counter++;
}
return counter;
}
}

/// <summary>
/// Return html part of <see cref="HtmlNode"/> based on <see cref="ReturnType"/>
Expand All @@ -749,11 +763,9 @@ internal static string GetHtmlForEncapsulation(HtmlNode node, ReturnType returnT
case ReturnType.OuterHtml:
return node.OuterHtml;
default:
throw new IndexOutOfRangeException("Unhandled ReturnType : " + returnType.ToString());
throw new InvalidNodeReturnTypeException(string.Format("Invalid ReturnType value {0}", returnType));
};
}


}


Expand All @@ -763,7 +775,7 @@ internal static string GetHtmlForEncapsulation(HtmlNode node, ReturnType returnT
public enum ReturnType
{
/// <summary>
/// The text between the start and end tags of the object.
/// The text between the start and end tags of the object.
/// </summary>
InnerText,

Expand Down Expand Up @@ -796,6 +808,9 @@ public sealed class HasXPathAttribute : Attribute
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class XPathAttribute : Attribute
{
private ReturnType _nodeReturnType;
internal bool IsNodeReturnTypeExplicitlySet { get; private set; }

/// <summary>
/// XPath Expression that is used to find related html node.
/// </summary>
Expand All @@ -809,7 +824,15 @@ public sealed class XPathAttribute : Attribute
/// <summary>
/// The methode of output
/// </summary>
public ReturnType NodeReturnType { get; set; }
public ReturnType NodeReturnType
{
get => _nodeReturnType;
set
{
_nodeReturnType = value;
IsNodeReturnTypeExplicitlySet = true;
}
}

/// <summary>
/// Specify Xpath to find related Html Node.
Expand All @@ -818,7 +841,7 @@ public sealed class XPathAttribute : Attribute
public XPathAttribute(string xpathString)
{
XPath = xpathString;
NodeReturnType = ReturnType.InnerText;
_nodeReturnType = ReturnType.InnerText;
}

/// <summary>
Expand All @@ -841,6 +864,7 @@ public XPathAttribute(string xpathString, string attributeName)
{
XPath = xpathString;
AttributeName = attributeName;
_nodeReturnType = ReturnType.InnerText;
}
}

Expand All @@ -862,18 +886,18 @@ public sealed class SkipNodeNotFoundAttribute : Attribute
public class NodeNotFoundException : Exception
{
/// <summary>
///
///
/// </summary>
public NodeNotFoundException() { }

/// <summary>
///
///
/// </summary>
/// <param name="message"></param>
public NodeNotFoundException(string message) : base(message) { }

/// <summary>
///
///
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
Expand All @@ -887,18 +911,18 @@ public NodeNotFoundException(string message, Exception inner) : base(message, in
public class NodeAttributeNotFoundException : Exception
{
/// <summary>
///
///
/// </summary>
public NodeAttributeNotFoundException() { }

/// <summary>
///
///
/// </summary>
/// <param name="message"></param>
public NodeAttributeNotFoundException(string message) : base(message) { }

/// <summary>
///
///
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
Expand All @@ -913,27 +937,47 @@ public class MissingXPathException : Exception
{

/// <summary>
///
///
/// </summary>
public MissingXPathException() { }

/// <summary>
///
///
/// </summary>
/// <param name="message"></param>
public MissingXPathException(string message) : base(message) { }

/// <summary>
///
///
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
public MissingXPathException(string message, Exception inner) : base(message, inner) { }
}


/// <summary>
/// Exception that occurs when an XPathAttribute annotation has an invalid ReturnType specified.
/// </summary>
public class InvalidNodeReturnTypeException : Exception
{
/// <summary>
///
/// </summary>
/// <param name="message"></param>
public InvalidNodeReturnTypeException(string message)
: base(message) { }

/// <summary>
///
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
public InvalidNodeReturnTypeException(string message, Exception inner) : base(message, inner) { }
}
}

#if FX20
#if FX20
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method |
Expand Down
Loading

0 comments on commit 3999898

Please sign in to comment.