Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix encapsulated item with corresponding ReturnType #506

Merged
merged 2 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 43 additions & 84 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 @@ -29,7 +29,7 @@ public partial class HtmlNode
/// <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="FormatException">Why it's thrown.</exception>
/// <exception cref="Exception">Why it's thrown.</exception>
public T GetEncapsulatedData<T>()
{
Expand All @@ -50,7 +50,7 @@ public T GetEncapsulatedData<T>()
/// <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="FormatException">Why it's thrown.</exception>
/// <exception cref="Exception">Why it's thrown.</exception>
public T GetEncapsulatedData<T>(HtmlDocument htmlDocument)
{
Expand All @@ -72,7 +72,7 @@ public T GetEncapsulatedData<T>(HtmlDocument htmlDocument)
/// <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="FormatException">Why it's thrown.</exception>
/// <exception cref="Exception">Why it's thrown.</exception>
public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = null)
{
Expand Down Expand Up @@ -177,7 +177,7 @@ public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = n
{
HtmlDocument innerHtmlDocument = new HtmlDocument();

innerHtmlDocument.LoadHtml(htmlNode.InnerHtml);
innerHtmlDocument.LoadHtml(Tools.GetHtmlForEncapsulation(htmlNode, xPathAttribute.NodeReturnType));

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

Expand All @@ -192,7 +192,7 @@ 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);
}
Expand Down Expand Up @@ -295,7 +295,7 @@ public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = n
foreach (HtmlNode node in nodeCollection)
{
HtmlDocument innerHtmlDocument = new HtmlDocument();
innerHtmlDocument.LoadHtml(node.InnerHtml);
innerHtmlDocument.LoadHtml(Tools.GetHtmlForEncapsulation(node, xPathAttribute.NodeReturnType));

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

Expand Down Expand Up @@ -381,9 +381,6 @@ public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = n
}
#endregion targetObject_NOTDefined_XPath
}



}


Expand Down Expand Up @@ -602,34 +599,7 @@ internal static T GetNodeValueBasedOnXPathReturnType<T>(HtmlNode htmlNode, XPath
throw new ArgumentNullException("parameter xpathAttribute is null");
}

object result;
Type TType = typeof(T);

switch (xPathAttribute.NodeReturnType)
{
case ReturnType.InnerHtml:
{
result = Convert.ChangeType(htmlNode.InnerHtml, TType);
}
break;


case ReturnType.InnerText:
{
result = Convert.ChangeType(htmlNode.InnerText, TType);
}
break;

case ReturnType.OuterHtml:
{
result = Convert.ChangeType(htmlNode.OuterHtml, TType);
}
break;

default: throw new Exception();
}

return (T)result;
return (T)Convert.ChangeType(GetHtmlForEncapsulation(htmlNode, xPathAttribute.NodeReturnType), typeof(T));
}


Expand All @@ -654,41 +624,10 @@ internal static IList GetNodesValuesBasedOnXPathReturnType(HtmlNodeCollection ht


IList result = listGenericType.CreateIListOfType();

switch (xPathAttribute.NodeReturnType)
foreach (HtmlNode node in htmlNodeCollection)
{

case ReturnType.InnerHtml:
{
foreach (HtmlNode node in htmlNodeCollection)
{
result.Add(Convert.ChangeType(node.InnerHtml, listGenericType));
}
}
break;


case ReturnType.InnerText:
{
foreach (HtmlNode node in htmlNodeCollection)
{
result.Add(Convert.ChangeType(node.InnerText, listGenericType));
}
}
break;


case ReturnType.OuterHtml:
{
foreach (HtmlNode node in htmlNodeCollection)
{
result.Add(Convert.ChangeType(node.OuterHtml, listGenericType));
}
}
break;

result.Add(Convert.ChangeType(GetHtmlForEncapsulation(node, xPathAttribute.NodeReturnType), listGenericType));
}

return result;
}

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


/// <summary>
/// Return html part of <see cref="HtmlNode"/> based on <see cref="ReturnType"/>
/// </summary>
/// <param name="node">A htmlNode instance.</param>
/// <param name="returnType"><see cref="ReturnType"/></param>
/// <returns>Html part</returns>
/// <exception cref="IndexOutOfRangeException">Out of range to the <see cref="ReturnType"/></exception>
internal static string GetHtmlForEncapsulation(HtmlNode node, ReturnType returnType)
{
switch (returnType)
{
case ReturnType.InnerText:
return node.InnerText;
case ReturnType.InnerHtml:
return node.InnerHtml;
case ReturnType.OuterHtml:
return node.OuterHtml;
default:
throw new IndexOutOfRangeException("Unhandled ReturnType : " + returnType.ToString());
};
}
}


Expand All @@ -797,7 +756,7 @@ internal static int CountOfIEnumerable<T>(this IEnumerable<T> source)
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 @@ -896,18 +855,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 @@ -921,18 +880,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 @@ -947,18 +906,18 @@ 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>
Expand All @@ -967,7 +926,7 @@ public MissingXPathException(string message, Exception inner) : base(message, in

}

#if FX20
#if FX20
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using Xunit;

namespace HtmlAgilityPack.Tests.NetStandard2_0
Expand Down Expand Up @@ -29,8 +30,32 @@ public void Dictionary_Test()

Assert.NotNull(wort);
}

[Fact]
public void EncapsulatedOuterHtml_Test()
{
var html = @"
<div>
<a href='3.html' class='single'>3</a>
<div>hello
<a href='1.html'>1</a>
<a href='2.html'>2</a>
</div>
<div>world</div>
</div>
";
var document = new HtmlDocument();
document.LoadHtml(html);
var outerHtml = document.DocumentNode.GetEncapsulatedData<OuterHtml>();
Assert.True(outerHtml.Item3.Href == "3.html");
Assert.True(outerHtml.Item3.Name == "3");

Assert.True(outerHtml.Items.Count == 3);
Assert.True(outerHtml.Items.All(o => o.Href != null));
}
}


#region StackOverFlow_TestClasses

[HasXPath]
Expand Down Expand Up @@ -204,5 +229,29 @@ public class Example

#endregion Dictionary_TestClasses

#region Encapsulated outer html test classes

[HasXPath]
public class OuterHtml
{
[XPath("//a", ReturnType.OuterHtml)]
public List<OuterHtmlItem> Items { get; set; }

[XPath("//a[@class='single']", ReturnType.OuterHtml)]
public OuterHtmlItem Item3 { get; set; }


[HasXPath]
public class OuterHtmlItem
{
[XPath("a", "href")]
[SkipNodeNotFound]
public string Href { get; set; }

[XPath("a")]
[SkipNodeNotFound]
public string Name { get; set; }
}
}
#endregion
}