Skip to content

Commit

Permalink
Update code with: #447
Browse files Browse the repository at this point in the history
Update code with: #447
  • Loading branch information
JonathanMagnan committed Aug 9, 2021
1 parent 274a00b commit d820834
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 5 deletions.
15 changes: 14 additions & 1 deletion src/HtmlAgilityPack.Shared/HtmlAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class HtmlAttribute : IComparable
internal string _value;
internal int _valuelength;
internal int _valuestartindex;
private bool? _localUseOriginalName;

#endregion

Expand Down Expand Up @@ -83,7 +84,19 @@ public int ValueLength
get { return _valuelength; }
}

public bool UseOriginalName { get; set; } = false;
/// <summary>Gets or sets a value indicating whether the attribute should use the original name.</summary>
/// <value>True if the attribute should use the original name, false if not.</value>
public bool UseOriginalName
{
get
{
return this._localUseOriginalName ?? this.OwnerDocument.OptionDefaultUseOriginalName;
}
set
{
this._localUseOriginalName = value;
}
}

/// <summary>
/// Gets the qualified name of the attribute.
Expand Down
5 changes: 5 additions & 0 deletions src/HtmlAgilityPack.Shared/HtmlDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ public static bool DisableBehaviorTagP
/// </summary>
public string OptionStopperNodeName;

/// <summary>
/// Defines if attributes should use original names by default, rather than lower case. Default is false.
/// </summary>
public bool OptionDefaultUseOriginalName;

/// <summary>
/// Defines if the 'id' attribute must be specifically used. Default is true.
/// </summary>
Expand Down
11 changes: 7 additions & 4 deletions src/HtmlAgilityPack.Shared/HtmlNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ public string Name
if (_name == null)
_optimizedName = string.Empty;
else
_optimizedName = _name.ToLowerInvariant();
_optimizedName = this.OwnerDocument.OptionDefaultUseOriginalName ? _name : _name.ToLowerInvariant();
}

return _optimizedName;
Expand Down Expand Up @@ -2314,7 +2314,10 @@ internal void WriteAttribute(TextWriter outText, HtmlAttribute att)
}

var quoteType = OwnerDocument.GlobalAttributeValueQuote ?? att.QuoteType;
if (quoteType == AttributeValueQuote.Initial)
var isWithoutValue = quoteType == AttributeValueQuote.WithoutValue
|| (quoteType == AttributeValueQuote.Initial && string.IsNullOrEmpty(att.XmlValue));

if (quoteType == AttributeValueQuote.Initial && !string.IsNullOrEmpty(att.XmlValue))
{
quoteType = att.InternalQuoteType;
}
Expand All @@ -2327,7 +2330,7 @@ internal void WriteAttribute(TextWriter outText, HtmlAttribute att)
if (_ownerdocument.OptionOutputOriginalCase)
name = att.OriginalName;

if (quoteType != AttributeValueQuote.WithoutValue )
if (!isWithoutValue)
{
outText.Write(" " + name + "=" + quote + HtmlDocument.HtmlEncodeWithCompatibility(att.XmlValue, _ownerdocument.BackwardCompatibility) + quote);
}
Expand All @@ -2351,7 +2354,7 @@ internal void WriteAttribute(TextWriter outText, HtmlAttribute att)
}
}

if (quoteType != AttributeValueQuote.WithoutValue)
if (!isWithoutValue)
{
var value = quoteType == AttributeValueQuote.DoubleQuote ? !att.Value.StartsWith("@") ? att.Value.Replace("\"", "&quot;") :
att.Value : quoteType == AttributeValueQuote.SingleQuote ? att.Value.Replace("'", "&#39;") : att.Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="HtmlDocument.PreserveOriginalTest.cs" />
<Compile Include="HtmlDocumentTests.cs" />
<Compile Include="HtmlEntityTest.cs" />
<Compile Include="HtmlNode.Tests.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System;
using System.Xml.XPath;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace HtmlAgilityPack.Tests.fx._4._5
{
[TestClass]
public class HtmlDocumentPreserveOriginalTest
{
[TestMethod]
public void PreserveEmptyAttributesTest()
{
var d = new HtmlDocument();
d.OptionEmptyCollection = true;

d.GlobalAttributeValueQuote = AttributeValueQuote.Initial;

d.OptionDefaultUseOriginalName = true;
//d.OptionPreserveEmptyAttributes = true;

var html = @"
<form #editForm='ngForm' (ngSubmit)='OnSaveData()' name='globalForm' [dataSourceContext]='detailDataSourceContext'>
<page editable (beginEdit)='OnBeginEdit()' (cancelEdit)='OnCancelEdit($event)'>
<page-header pageHeaderIcon='_Lea_ mdi mdi-code-json'>
<page-header-actions>
<list-counter formErrorsCounter></list-counter>
<button mat-button *hasEveryPermission='permissionConstants.LeaProdutos.edit' enterEditButton>
</button>
<button mat-button *hasEveryPermission='permissionConstants.LeaProdutos.edit' cancelEditButton>
</button>
<button mat-button *hasEveryPermission='permissionConstants.LeaProdutos.edit' type='submit' confirmEditButton>
</button>
<refresh-button></refresh-button>
</page-header-actions>
</page-header>
<page-body>
</page-body>
</page>
</form>
";
d.LoadHtml(html);

var outer = d.DocumentNode.OuterHtml;

var xpath = XPathExpression.Compile("/form/page/page-header/page-header-actions/button[@enterEditButton]");
var nodes = d.DocumentNode.SelectNodes(xpath);

Assert.AreEqual(nodes?.Count, 1, "xpath expression should return 1 node");
Assert.AreEqual(d.DocumentNode.OuterHtml, html);
}

[TestMethod]
public void PreserveOriginalCasingTest()
{
var d = new HtmlDocument();
d.OptionEmptyCollection = true;

d.GlobalAttributeValueQuote = AttributeValueQuote.Initial;

d.OptionDefaultUseOriginalName = true;
//d.OptionPreserveEmptyAttributes = true;

var html = @"
<form #editForm='ngForm' (ngSubmit)='OnSaveData()' name='globalForm' [dataSourceContext]='detailDataSourceContext'>
<page editable (beginEdit)='OnBeginEdit()' (cancelEdit)='OnCancelEdit($event)'>
<page-Header pageHeaderIcon='_Lea_ mdi mdi-code-json'>
<page-Header-Actions>
<list-counter formErrorsCounter></list-counter>
<button mat-button *hasEveryPermission='permissionConstants.LeaProdutos.edit' enterEditButton>
</button>
<button mat-button *hasEveryPermission='permissionConstants.LeaProdutos.edit' cancelEditButton>
</button>
<button mat-button *hasEveryPermission='permissionConstants.LeaProdutos.edit' type='submit' confirmEditButton>
</button>
<refresh-button></refresh-button>
</page-Header-Actions>
</page-Header>
<page-body>
</page-body>
</page>
</form>
";
d.LoadHtml(html);

var xpath = XPathExpression.Compile("/form/page/page-Header/page-Header-Actions/button[@enterEditButton]");
var nodes = d.DocumentNode.SelectNodes(xpath);

Assert.AreEqual(nodes?.Count, 1, "xpath expression should return 1 node");
Assert.AreEqual(d.DocumentNode.OuterHtml, html);
}
}
}
21 changes: 21 additions & 0 deletions src/Tests/HtmlAgilityPack.Tests.Net45/HtmlDocumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,27 @@ public void CreateElement()
Assert.AreEqual(a.NodeType, HtmlNodeType.Element);
}

[Test]
public void TestBr()
{
{
var html = @" </br>a</br>";

var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
var docNode = doc.DocumentNode.InnerHtml;
Assert.AreEqual(4, doc.DocumentNode.ChildNodes.Count);
}
{
var html = @" <br>a<br>";

var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
var docNode = doc.DocumentNode.InnerHtml;
Assert.AreEqual(4, doc.DocumentNode.ChildNodes.Count);
}
}

//[Test]
//public void CreateTextNode()
//{
Expand Down

0 comments on commit d820834

Please sign in to comment.