RaUI/Source/MyDb/HtmlAgilityPack.Shared/HtmlNode.Encapsulator.cs
鑫Intel a1d6dce946 ### 2021-08-03更新
------
#### MyDbV4    V3.0.2108.0301
- *.[新增]新增内置HtmlAgilityPack组件。
2021-08-30 19:47:56 +08:00

981 lines
39 KiB
C#

// 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.
#if !METRO && !NETSTANDARD1_3
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Xml.XPath;
namespace HtmlAgilityPack
{
public partial class HtmlNode
{
/// <summary>
/// Fill an object and go through it's properties and fill them too.
/// </summary>
/// <typeparam name="T">Type of object to want to fill. It should have atleast one property that defined XPath.</typeparam>
/// <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="Exception">Why it's thrown.</exception>
public T GetEncapsulatedData<T>()
{
return (T)GetEncapsulatedData(typeof(T), null);
}
/// <summary>
/// Fill an object and go through it's properties and fill them too.
/// </summary>
/// <typeparam name="T">Type of object to want to fill. It should have atleast one property that defined XPath.</typeparam>
/// <param name="htmlDocument">If htmlDocument includes data , leave this parameter null. Else pass your specific htmldocument.</param>
/// <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="Exception">Why it's thrown.</exception>
public T GetEncapsulatedData<T>(HtmlDocument htmlDocument)
{
return (T)GetEncapsulatedData(typeof(T), htmlDocument);
}
/// <summary>
/// Fill an object and go through it's properties and fill them too.
/// </summary>
/// <param name="targetType">Type of object to want to fill. It should have atleast one property that defined XPath.</param>
/// <param name="htmlDocument">If htmlDocument includes data , leave this parameter null. Else pass your specific htmldocument.</param>
/// <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="Exception">Why it's thrown.</exception>
public object GetEncapsulatedData(Type targetType, HtmlDocument htmlDocument = null)
{
#region SettingPrerequisite
if (targetType == null)
{
throw new ArgumentNullException("Parameter targetType is null");
}
HtmlDocument source;
if (htmlDocument == null)
{
source = OwnerDocument;
}
else
{
source = htmlDocument;
}
object targetObject;
if (targetType.IsInstantiable() == false) // if it can not create instanse of T because of lack of constructor in type T.
{
throw new MissingMethodException("Parameterless Constructor excpected for " + targetType.FullName);
}
else
{
targetObject = Activator.CreateInstance(targetType);
}
#endregion SettingPrerequisite
#region targetObject_Defined_XPath
if (targetType.IsDefinedAttribute(typeof(HasXPathAttribute)) == true) // Object has xpath attribute (Defined HasXPath)
{
// Store list of properties that defined xpath attribute
IEnumerable<PropertyInfo> validProperties = targetType.GetPropertiesDefinedXPath();
if (validProperties.CountOfIEnumerable() == 0) // if no XPath property exist in type T while T defined HasXpath attribute.
{
throw new MissingXPathException("Type " + targetType.FullName +
" defined HasXPath Attribute but it does not have any property with XPath Attribte.");
}
else
{
// Fill targetObject variable Properties ( T targetObject )
foreach (PropertyInfo propertyInfo in validProperties)
{
// Get xpath attribute from valid properties
// for .Net old versions:
XPathAttribute xPathAttribute = (propertyInfo.GetCustomAttributes(typeof(XPathAttribute), false) as IList)[0] as XPathAttribute;
#region Property_IsNOT_IEnumerable
if (propertyInfo.IsIEnumerable() == false) // Property is None-IEnumerable
{
HtmlNode htmlNode = null;
// try to fill htmlNode based on XPath given
try
{
htmlNode = source.DocumentNode.SelectSingleNode(xPathAttribute.XPath);
}
catch (XPathException ex) // if it can not select node based on given xpath
{
throw new XPathException(ex.Message + " That means you have a syntax error in XPath property of this Property : " +
propertyInfo.PropertyType.FullName + " " + propertyInfo.Name);
}
catch (Exception ex)
{
throw new NodeNotFoundException("Cannot find node with giving XPath to bind to " +
propertyInfo.PropertyType.FullName + " " + propertyInfo.Name, ex);
}
if (htmlNode == null) // If Encapsulator could not find Node.
{
if (propertyInfo.IsDefined(typeof(SkipNodeNotFoundAttribute), false) == true)
{
// set default value.
//throw new Exception("Okey !");
}
else
{
throw new NodeNotFoundException("Cannot find node with giving XPath to bind to " +
propertyInfo.PropertyType.FullName + " " + propertyInfo.Name);
}
}
else // if htmlNode is not null (Encapsulator find the Node)
{
#region Property_Is_HasXPath_UserDefinedClass
// Property is None-IEnumerable HasXPath-user-defined class
if (propertyInfo.PropertyType.IsDefinedAttribute(typeof(HasXPathAttribute)) == true)
{
HtmlDocument innerHtmlDocument = new HtmlDocument();
innerHtmlDocument.LoadHtml(htmlNode.InnerHtml);
object o = GetEncapsulatedData(propertyInfo.PropertyType, innerHtmlDocument);
propertyInfo.SetValue(targetObject, o, null);
}
#endregion Property_Is_HasXPath_UserDefinedClass
#region Property_Is_SimpleType
// Property is None-IEnumerable value-type or .Net class or user-defined class.
// AND does not deifned xpath and shouldn't have property that defined xpath.
else
{
string result = string.Empty;
if (xPathAttribute.AttributeName == null) // It target value of HTMLTag
{
result = Tools.GetNodeValueBasedOnXPathReturnType<string>(htmlNode, xPathAttribute);
}
else // It target attribute of HTMLTag
{
result = htmlNode.GetAttributeValue(xPathAttribute.AttributeName, null);
}
if (result == null)
{
throw new NodeAttributeNotFoundException("Can not find " +
xPathAttribute.AttributeName + " Attribute in " + htmlNode.Name +
" related to " + propertyInfo.PropertyType.FullName + " " + propertyInfo.Name);
}
object resultCastedToTargetPropertyType;
try
{
resultCastedToTargetPropertyType = Convert.ChangeType(result, propertyInfo.PropertyType);
}
catch (FormatException)
{
throw new FormatException("Can not convert Invalid string to " + propertyInfo.PropertyType.FullName + " " + propertyInfo.Name);
}
catch (Exception ex)
{
throw new Exception("Unhandled Exception : " + ex.Message);
}
propertyInfo.SetValue(targetObject, resultCastedToTargetPropertyType, null);
}
#endregion Property_Is_SimpleType
}
}
#endregion Property_IsNOT_IEnumerable
#region Property_Is_IEnumerable
else // Property is IEnumerable<T>
{
IList<Type> T_Types = propertyInfo.GetGenericTypes() as IList<Type>; // Get T type
if (T_Types == null || T_Types.Count == 0)
{
throw new ArgumentException(propertyInfo.Name + " should have one generic argument.");
}
else if (T_Types.Count > 1)
{
throw new ArgumentException(propertyInfo.Name + " should have one generic argument.");
}
else if (T_Types.Count == 1) // It is NOT something like Dictionary<Tkey , Tvalue>
{
HtmlNodeCollection nodeCollection;
// try to fill nodeCollection based on given xpath.
try
{
nodeCollection = source.DocumentNode.SelectNodes(xPathAttribute.XPath);
}
catch (XPathException ex)
{
throw new XPathException(ex.Message + " That means you have a syntax error in XPath property of this Property : " +
propertyInfo.PropertyType.FullName + " " + propertyInfo.Name);
}
catch (Exception ex)
{
throw new NodeNotFoundException("Cannot find node with giving XPath to bind to " +
propertyInfo.PropertyType.FullName + " " + propertyInfo.Name, ex);
}
if (nodeCollection == null || nodeCollection.Count == 0)
{
if (propertyInfo.IsDefined(typeof(SkipNodeNotFoundAttribute), false) == true)
{
// set default value.
//throw new Exception("Okey !");
}
else
{
throw new NodeNotFoundException("Cannot find node with giving XPath to bind to " +
propertyInfo.PropertyType.FullName + " " + propertyInfo.Name);
}
}
else
{
IList result = T_Types[0].CreateIListOfType();
#region Property_Is_IEnumerable<HasXPath-UserDefinedClass>
if (T_Types[0].IsDefinedAttribute(typeof(HasXPathAttribute)) == true) // T is IEnumerable HasXPath-user-defined class (T type Defined XPath properties)
{
foreach (HtmlNode node in nodeCollection)
{
HtmlDocument innerHtmlDocument = new HtmlDocument();
innerHtmlDocument.LoadHtml(node.InnerHtml);
object o = GetEncapsulatedData(T_Types[0], innerHtmlDocument);
result.Add(o);
}
}
#endregion Property_Is_IEnumerable<HasXPath-UserDefinedClass>
#region Property_Is_IEnumerable<SimpleClass>
else // T is value-type or .Net class or user-defined class ( without xpath )
{
if (xPathAttribute.AttributeName == null) // It target value
{
try
{
result = Tools.GetNodesValuesBasedOnXPathReturnType(nodeCollection, xPathAttribute, T_Types[0]);
}
catch (FormatException)
{
throw new FormatException("Can not convert Invalid string in node collection to " + T_Types[0].FullName + " " + propertyInfo.Name);
}
catch (Exception ex)
{
throw new Exception("Unhandled Exception : " + ex.Message);
}
}
else // It target attribute
{
foreach (HtmlNode node in nodeCollection)
{
string nodeAttributeValue = node.GetAttributeValue(xPathAttribute.AttributeName, null);
if (nodeAttributeValue == null)
{
throw new NodeAttributeNotFoundException("Can not find " + xPathAttribute.AttributeName + " Attribute in " + node.Name + " related to " +
propertyInfo.PropertyType.FullName + " " + propertyInfo.Name);
}
object resultCastedToTargetPropertyType;
try
{
resultCastedToTargetPropertyType = Convert.ChangeType(nodeAttributeValue, T_Types[0]);
}
catch (FormatException) // if it can not cast result(string) to type of property.
{
throw new FormatException("Can not convert Invalid string to " + T_Types[0].FullName + " " + propertyInfo.Name);
}
catch (Exception ex)
{
throw new Exception("Unhandled Exception : " + ex.Message);
}
result.Add(resultCastedToTargetPropertyType);
}
}
}
#endregion Property_Is_IEnumerable<SimpleClass>
if (result == null || result.Count == 0)
{
throw new Exception("Cannot fill " + propertyInfo.PropertyType.FullName + " " + propertyInfo.Name + " because it is null.");
}
propertyInfo.SetValue(targetObject, result, null);
}
}
}
#endregion Property_Is_IEnumerable
}
return targetObject;
}
}
#endregion targetObject_Defined_XPath
#region targetObject_NOTDefined_XPath
else // Object doesen't have xpath attribute
{
throw new MissingXPathException("Type T must define HasXPath attribute and include properties with XPath attribute.");
}
#endregion targetObject_NOTDefined_XPath
}
}
/// <summary>
/// Includes tools that GetEncapsulatedData method uses them.
/// </summary>
internal static class Tools
{
/// <summary>
/// Determine if a type define an attribute or not , supporting both .NetStandard and .NetFramework2.0
/// </summary>
/// <param name="type">Type you want to test it.</param>
/// <param name="attributeType">Attribute that type must have or not.</param>
/// <returns>If true , The type parameter define attributeType parameter.</returns>
internal static bool IsDefinedAttribute(this Type type, Type attributeType)
{
if (type == null)
{
throw new ArgumentNullException("Parameter type is null when checking type defined attributeType or not.");
}
if (attributeType == null)
{
throw new ArgumentNullException("Parameter attributeType is null when checking type defined attributeType or not.");
}
#if !(NETSTANDARD1_3 || NETSTANDARD1_6)
if (type.IsDefined(attributeType, false) == true)
{
return true;
}
else
{
return false;
}
#endif
#if NETSTANDARD1_3 || NETSTANDARD1_6
if (type.GetTypeInfo().IsDefined(attributeType) == true)
{
return true;
}
else
{
return false;
}
#endif
throw new Exception("Can't Target any platform when checking " + type.FullName + " is a " + attributeType.FullName + " or not.");
}
/// <summary>
/// Retrive properties of type that defined <see cref="XPathAttribute"/>.
/// </summary>
/// <param name="type">Type that you want to find it's XPath-Defined properties.</param>
/// <returns>IEnumerable of property infos of a type , that defined specific attribute.</returns>
internal static IEnumerable<PropertyInfo> GetPropertiesDefinedXPath(this Type type)
{
if (type == null)
{
throw new ArgumentNullException("Parameter type is null while retrieving properties defined XPathAttribute of Type type.");
}
PropertyInfo[] properties = null;
#if !(NETSTANDARD1_3 || NETSTANDARD1_6)
properties = type.GetProperties();
#endif
#if NETSTANDARD1_3 || NETSTANDARD1_6
properties = type.GetTypeInfo().GetProperties();
#endif
return properties.HAPWhere(x => x.IsDefined(typeof(XPathAttribute), false) == true);
throw new Exception("Can't Target any platform while retrieving properties defined XPathAttribute of Type type.");
}
/// <summary>
/// Determine if a <see cref="PropertyInfo"/> has implemented <see cref="IEnumerable"/> BUT <see cref="string"/> is considered as NONE-IEnumerable !
/// </summary>
/// <param name="propertyInfo">The property info you want to test.</param>
/// <returns>True if property info is IEnumerable.</returns>
internal static bool IsIEnumerable(this PropertyInfo propertyInfo)
{
//return propertyInfo.PropertyType.GetInterface(typeof(IEnumerable<>).FullName) != null;
if (propertyInfo == null)
{
throw new ArgumentNullException("Parameter propertyInfo is null while checking propertyInfo for being IEnumerable or not.");
}
if (propertyInfo.PropertyType == typeof(string))
{
return false;
}
else
{
#if !(NETSTANDARD1_3 || NETSTANDARD1_6)
return typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType);
#endif
#if NETSTANDARD1_3 || NETSTANDARD1_6
return typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(propertyInfo.PropertyType);
#endif
throw new Exception("Can't Target any platform while checking propertyInfo for being IEnumerable or not.");
}
}
/// <summary>
/// Returns T type(first generic type) of <see cref="IEnumerable{T}"/> or <see cref="List{T}"/>.
/// </summary>
/// <param name="propertyInfo">IEnumerable-Implemented property</param>
/// <returns>List of generic types.</returns>
internal static IEnumerable<Type> GetGenericTypes(this PropertyInfo propertyInfo)
{
if (propertyInfo == null)
{
throw new ArgumentNullException("Parameter propertyInfo is null while Getting generic types of Property.");
}
#if !(NETSTANDARD1_3 || NETSTANDARD1_6)
return propertyInfo.PropertyType.GetGenericArguments();
#endif
#if NETSTANDARD1_3 || NETSTANDARD1_6
return propertyInfo.PropertyType.GetTypeInfo().GetGenericArguments();
#endif
throw new Exception("Can't Target any platform while Getting generic types of Property.");
}
/// <summary>
/// Find and Return a mehtod that defined in a class by it's name.
/// </summary>
/// <param name="type">Type of class include requested method.</param>
/// <param name="methodName">Name of requested method as string.</param>
/// <returns>Method info of requested method.</returns>
internal static MethodInfo GetMethodByItsName(this Type type, string methodName)
{
if (type == null)
{
throw new ArgumentNullException("Parameter type is null while Getting method from it.");
}
if (methodName == null || methodName == "")
{
throw new ArgumentNullException("Parameter methodName is null while Getting method from Type type.");
}
#if !(NETSTANDARD1_3 || NETSTANDARD1_6)
return type.GetMethod(methodName);
#endif
#if NETSTANDARD1_3 || NETSTANDARD1_6
return type.GetTypeInfo().GetMethod(methodName);
#endif
throw new Exception("Can't Target any platform while getting Method methodName from Type type.");
}
/// <summary>
/// Create <see cref="IList"/> of given type.
/// </summary>
/// <param name="type">Type that you want to make a List of it.</param>
/// <returns>Returns IList of given type.</returns>
internal static IList CreateIListOfType(this Type type)
{
if (type == null)
{
throw new ArgumentNullException("Parameter type is null while creating List<type>.");
}
Type listType = typeof(List<>);
Type constructedListType = listType.MakeGenericType(type);
return Activator.CreateInstance(constructedListType) as IList;
}
/// <summary>
/// Returns the part of value of <see cref="HtmlNode"/> you want as .
/// </summary>
/// <param name="htmlNode">A htmlNode instance.</param>
/// <param name="xPathAttribute">Attribute that includes ReturnType</param>
/// <returns>String that choosen from HtmlNode as result.</returns>
internal static T GetNodeValueBasedOnXPathReturnType<T>(HtmlNode htmlNode, XPathAttribute xPathAttribute)
{
if (htmlNode == null)
{
throw new ArgumentNullException("parameter html node is null");
}
if (xPathAttribute == null)
{
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;
}
/// <summary>
/// Returns parts of values of <see cref="HtmlNode"/> you want as <see cref="IList{T}"/>.
/// </summary>
/// <param name="htmlNodeCollection"><see cref="HtmlNodeCollection"/> that you want to retrive each <see cref="HtmlNode"/> value.</param>
/// <param name="xPathAttribute">A <see cref="XPathAttribute"/> instnce incules <see cref="ReturnType"/>.</param>
/// <param name="listGenericType">Type of IList generic you want.</param>
/// <returns></returns>
internal static IList GetNodesValuesBasedOnXPathReturnType(HtmlNodeCollection htmlNodeCollection, XPathAttribute xPathAttribute, Type listGenericType)
{
if (htmlNodeCollection == null || htmlNodeCollection.Count == 0)
{
throw new ArgumentNullException("parameter htmlNodeCollection is null or empty.");
}
if (xPathAttribute == null)
{
throw new ArgumentNullException("parameter xpathAttribute is null");
}
IList result = listGenericType.CreateIListOfType();
switch (xPathAttribute.NodeReturnType)
{
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;
}
return result;
}
/// <summary>
/// Simulate Func method to use in Lambada Expression.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="arg"></param>
/// <returns></returns>
internal delegate TResult HAPFunc<T, TResult>(T arg);
/// <summary>
/// This method works like Where method in LINQ.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="predicate"></param>
/// <returns></returns>
internal static IEnumerable<TSource> HAPWhere<TSource>(this IEnumerable<TSource> source, HAPFunc<TSource, bool> predicate)
{
foreach (TSource item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
/// <summary>
/// Check if the type can instantiated.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
internal static bool IsInstantiable(this Type type)
{
if (type == null)
{
throw new ArgumentNullException("type is null");
}
#if !(NETSTANDARD1_3 || NETSTANDARD1_6)
// checking for having parameterless constructor.
if (type.GetConstructor(Type.EmptyTypes) == null)
{
return false;
}
else
{
return true;
}
#endif
#if NETSTANDARD1_3 || NETSTANDARD1_6
// checking for having parameterless constructor.
if (type.GetTypeInfo().DeclaredConstructors.HAPWhere(x => x.GetParameters().Length == 0).CountOfIEnumerable() == 0)
{
return false;
}
else
{
return true;
}
#endif
throw new Exception("Can't Target any platform while getting Method methodName from Type type.");
}
/// <summary>
/// Returns count of elements stored in IEnumerable of T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
internal static int CountOfIEnumerable<T>(this IEnumerable<T> source)
{
if (source == null)
{
throw new ArgumentNullException("Parameter source is null while counting the IEnumerable");
}
int counter = 0;
foreach (T item in source)
{
counter++;
}
return counter;
}
}
/// <summary>
/// Specify which part of <see cref="HtmlNode"/> is requested.
/// </summary>
public enum ReturnType
{
/// <summary>
/// The text between the start and end tags of the object.
/// </summary>
InnerText,
/// <summary>
/// The HTML between the start and end tags of the object
/// </summary>
InnerHtml,
/// <summary>
/// The object and its content in HTML
/// </summary>
OuterHtml
}
/// <summary>
/// Just mark and flag classes to show they have properties that defined <see cref="XPathAttribute"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class HasXPathAttribute : Attribute
{
}
/// <summary>
/// Includes XPath and <see cref="NodeReturnType"/>. XPath for finding html tags and <see cref="NodeReturnType"/> for specify which part of <see cref="HtmlNode"/> you want to return.
/// </summary>
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class XPathAttribute : Attribute
{
/// <summary>
/// XPath Expression that is used to find related html node.
/// </summary>
public string XPath { get; }
/// <summary>
/// Html Attribute name
/// </summary>
public string AttributeName { get; set; }
/// <summary>
/// The methode of output
/// </summary>
public ReturnType NodeReturnType { get; set; }
/// <summary>
/// Specify Xpath to find related Html Node.
/// </summary>
/// <param name="xpathString"></param>
public XPathAttribute(string xpathString)
{
XPath = xpathString;
NodeReturnType = ReturnType.InnerText;
}
/// <summary>
/// Specify Xpath to find related Html Node.
/// </summary>
/// <param name="xpathString"></param>
/// <param name="nodeReturnType">Specify you want the output include html text too.</param>
public XPathAttribute(string xpathString, ReturnType nodeReturnType)
{
XPath = xpathString;
NodeReturnType = nodeReturnType;
}
/// <summary>
/// Specify Xpath and Attribute to find related Html Node and its attribute value.
/// </summary>
/// <param name="xpathString"></param>
/// <param name="attributeName"></param>
public XPathAttribute(string xpathString, string attributeName)
{
XPath = xpathString;
AttributeName = attributeName;
}
}
/// <summary>
/// Tagging a property with this Attribute make Encapsulator to ignore that property if it causes an error.
/// </summary>
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class SkipNodeNotFoundAttribute : Attribute
{
}
/// <summary>
/// Exception that often occures when there is no way to bind a XPath to a Html Tag.
/// </summary>
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>
public NodeNotFoundException(string message, Exception inner) : base(message, inner) { }
}
/// <summary>
/// Exception that often occures when there is no way to bind a XPath to a HtmlTag Attribute.
/// </summary>
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>
public NodeAttributeNotFoundException(string message, Exception inner) : base(message, inner) { }
}
/// <summary>
/// Exception that often occures when there is no property that assigned with XPath Property in Class.
/// </summary>
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) { }
}
}
#if FX20
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method |
AttributeTargets.Class | AttributeTargets.Assembly)]
public sealed class ExtensionAttribute : Attribute
{
}
}
#endif
#endif