From e6ecabf34c300273cc3c2448bad5b7ccb339d43b Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Tue, 22 Oct 2024 23:25:01 +0200
Subject: [PATCH 01/13] Support deprecrated `align` attribute for block #171
---
src/Html2OpenXml/Expressions/BlockElementExpression.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Html2OpenXml/Expressions/BlockElementExpression.cs b/src/Html2OpenXml/Expressions/BlockElementExpression.cs
index 7ae7026..62bc8ce 100644
--- a/src/Html2OpenXml/Expressions/BlockElementExpression.cs
+++ b/src/Html2OpenXml/Expressions/BlockElementExpression.cs
@@ -168,8 +168,8 @@ protected override void ComposeStyles (ParsingContext context)
};
}
- var attrValue = styleAttributes!["text-align"];
- JustificationValues? align = Converter.ToParagraphAlign(attrValue);
+ JustificationValues? align = Converter.ToParagraphAlign(styleAttributes!["text-align"]);
+ if (!align.HasValue) align = Converter.ToParagraphAlign(node.GetAttribute("align"));
if (align.HasValue)
{
paraProperties.Justification = new() { Val = align };
From 78f026c3d589e393d9603abb3f16839cd1c6a022 Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Mon, 4 Nov 2024 23:17:01 +0100
Subject: [PATCH 02/13] Support center image with margin auto #171
---
.../Expressions/Image/ImageExpressionBase.cs | 39 ++++++++++++++-----
.../Utilities/AngleSharpExtensions.cs | 9 +++++
.../Utilities/OpenXmlExtensions.cs | 2 -
test/HtmlToOpenXml.Tests/ImgTests.cs | 15 +++++++
4 files changed, 54 insertions(+), 11 deletions(-)
diff --git a/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs b/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs
index 3cf0422..0f77f42 100644
--- a/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs
+++ b/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs
@@ -12,7 +12,6 @@
using System.Collections.Generic;
using System.Linq;
using DocumentFormat.OpenXml;
-using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using a = DocumentFormat.OpenXml.Drawing;
@@ -26,6 +25,12 @@ namespace HtmlToOpenXml.Expressions;
///
abstract class ImageExpressionBase(AngleSharp.Dom.IElement node) : HtmlDomExpression
{
+ private readonly RunProperties runProperties = new();
+ private readonly ParagraphProperties paraProperties = new();
+ // some style attributes, such as borders, will convert this node to a framed container
+ private bool renderAsFramed;
+
+
///
public override IEnumerable Interpret (ParsingContext context)
{
@@ -35,16 +40,17 @@ public override IEnumerable Interpret (ParsingContext context)
return [];
Run run = new(drawing);
- Border border = ComposeStyles();
- if (border.Val?.Equals(BorderValues.None) == false)
- {
- run.RunProperties ??= new();
- run.RunProperties.Border = border;
- }
+ ComposeStyles();
+
+ if (runProperties.HasChildren)
+ run.RunProperties = runProperties;
+
+ if (renderAsFramed)
+ return [new Paragraph(paraProperties, run)];
return [run];
}
- private Border ComposeStyles ()
+ private void ComposeStyles ()
{
var styleAttributes = node.GetStyles();
var border = new Border() { Val = BorderValues.None };
@@ -66,7 +72,22 @@ private Border ComposeStyles ()
border.Size = (uint) borderWidth.ValueInPx * 4;
}
}
- return border;
+
+ if (border.Val?.Equals(BorderValues.None) == false)
+ {
+ runProperties.Border = border;
+ }
+
+ // if the layout is not inline and both left and right are auto, image appears centered
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/margin-left
+ var margin = styleAttributes.GetMargin("margin");
+ if (margin.Left.Type == UnitMetric.Auto
+ && margin.Right.Type == UnitMetric.Auto
+ && !AngleSharpExtensions.IsInlineLayout(styleAttributes["display"]))
+ {
+ paraProperties.Justification = new() { Val = JustificationValues.Center };
+ renderAsFramed = true;
+ }
}
///
diff --git a/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs b/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs
index 3d89624..bb397a2 100644
--- a/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs
+++ b/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs
@@ -153,4 +153,13 @@ public static string CollapseLineBreaks(this string str)
return new string(chars, 0, length);
}
+
+ ///
+ /// Determines whether the layout mode is inline vs block or flex.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsInlineLayout(string? displayMode)
+ {
+ return displayMode?.StartsWith("inline", StringComparison.OrdinalIgnoreCase) == true;
+ }
}
\ No newline at end of file
diff --git a/src/Html2OpenXml/Utilities/OpenXmlExtensions.cs b/src/Html2OpenXml/Utilities/OpenXmlExtensions.cs
index 5242f49..905ba21 100755
--- a/src/Html2OpenXml/Utilities/OpenXmlExtensions.cs
+++ b/src/Html2OpenXml/Utilities/OpenXmlExtensions.cs
@@ -9,11 +9,9 @@
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*/
-using System;
using System.Runtime.CompilerServices;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
-using DocumentFormat.OpenXml.Drawing.Wordprocessing;
namespace HtmlToOpenXml;
diff --git a/test/HtmlToOpenXml.Tests/ImgTests.cs b/test/HtmlToOpenXml.Tests/ImgTests.cs
index 15e5596..f335991 100644
--- a/test/HtmlToOpenXml.Tests/ImgTests.cs
+++ b/test/HtmlToOpenXml.Tests/ImgTests.cs
@@ -219,6 +219,21 @@ public async Task ParseIntoDocumentPart_ReturnsImageParentedToPart (Type openXml
AssertThatOpenXmlDocumentIsValid();
}
+ [TestCase("block", ExpectedResult = true)]
+ [TestCase("flex", ExpectedResult = true)]
+ [TestCase("inline", ExpectedResult = false)]
+ public bool CenterImg_ReturnsFramedImg(string displayMode)
+ {
+ var elements = converter.Parse($@"");
+
+ Assert.That(elements, Has.Count.EqualTo(1));
+ Assert.That(elements[0], Is.TypeOf());
+ AssertIsImg(mainPart, elements[0]);
+ return elements[0].GetFirstChild()?.
+ Justification?.Val?.Value == JustificationValues.Center;
+ }
+
private static (Drawing, ImagePart) AssertIsImg (OpenXmlPartContainer container, OpenXmlElement paragraph)
{
var run = paragraph.GetFirstChild();
From 25eba151c8d99d5f8b6c26ac23c20f81252d8fd5 Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Fri, 8 Nov 2024 21:43:52 +0100
Subject: [PATCH 03/13] Improve code behaviour intent on centered image
---
.../Expressions/Image/ImageExpressionBase.cs | 2 +-
src/Html2OpenXml/Utilities/AngleSharpExtensions.cs | 5 +++--
test/HtmlToOpenXml.Tests/ImgTests.cs | 9 +++++----
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs b/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs
index 0f77f42..06fb089 100644
--- a/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs
+++ b/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs
@@ -83,7 +83,7 @@ private void ComposeStyles ()
var margin = styleAttributes.GetMargin("margin");
if (margin.Left.Type == UnitMetric.Auto
&& margin.Right.Type == UnitMetric.Auto
- && !AngleSharpExtensions.IsInlineLayout(styleAttributes["display"]))
+ && !AngleSharpExtensions.IsInlineLayout(styleAttributes["display"], "inline-block"))
{
paraProperties.Justification = new() { Val = JustificationValues.Center };
renderAsFramed = true;
diff --git a/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs b/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs
index bb397a2..085f7d4 100644
--- a/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs
+++ b/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs
@@ -158,8 +158,9 @@ public static string CollapseLineBreaks(this string str)
/// Determines whether the layout mode is inline vs block or flex.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool IsInlineLayout(string? displayMode)
+ public static bool IsInlineLayout(string? displayMode, string defaultLayout)
{
- return displayMode?.StartsWith("inline", StringComparison.OrdinalIgnoreCase) == true;
+ return (displayMode ?? defaultLayout)
+ .StartsWith("inline", StringComparison.OrdinalIgnoreCase) == true;
}
}
\ No newline at end of file
diff --git a/test/HtmlToOpenXml.Tests/ImgTests.cs b/test/HtmlToOpenXml.Tests/ImgTests.cs
index f335991..45aa66d 100644
--- a/test/HtmlToOpenXml.Tests/ImgTests.cs
+++ b/test/HtmlToOpenXml.Tests/ImgTests.cs
@@ -219,12 +219,13 @@ public async Task ParseIntoDocumentPart_ReturnsImageParentedToPart (Type openXml
AssertThatOpenXmlDocumentIsValid();
}
- [TestCase("block", ExpectedResult = true)]
- [TestCase("flex", ExpectedResult = true)]
- [TestCase("inline", ExpectedResult = false)]
+ [TestCase("display:block", ExpectedResult = true)]
+ [TestCase("display:flex", ExpectedResult = true)]
+ [TestCase("display:inline", ExpectedResult = false)]
+ [TestCase("", ExpectedResult = false)]
public bool CenterImg_ReturnsFramedImg(string displayMode)
{
- var elements = converter.Parse($@"");
Assert.That(elements, Has.Count.EqualTo(1));
From d506001c738ec3c272cf216f3fdc98ddfb1cc6ad Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Sun, 10 Nov 2024 17:36:19 +0100
Subject: [PATCH 04/13] Improve regex parsing to skip empty attribute and
handle html encoded separators to avoid an extra call to HtmlDecode
---
.../Collections/HtmlAttributeCollection.cs | 11 ++---------
test/HtmlToOpenXml.Tests/StyleTests.cs | 16 ++++++++++++++++
2 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs
index bdccb5f..0c1c686 100755
--- a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs
+++ b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs
@@ -20,8 +20,7 @@ namespace HtmlToOpenXml;
///
sealed class HtmlAttributeCollection
{
- private static readonly Regex stripStyleAttributesRegex = new(@"(?.+?):\s*(?[^;]+);*\s*");
-
+ private static readonly Regex stripStyleAttributesRegex = new(@"(?[^;\s]+)\s?(&\#58;|:)\s?(?[^;&]+)\s?(;|&\#59;)*");
private readonly Dictionary attributes = [];
@@ -37,13 +36,7 @@ public static HtmlAttributeCollection ParseStyle(string? htmlTag)
// Encoded ':' and ';' characters are valid for browser but not handled by the regex (bug #13812 reported by robin391)
// ex=
- MatchCollection matches = stripStyleAttributesRegex.Matches(
-#if NET5_0_OR_GREATER
- System.Web.HttpUtility.HtmlDecode(htmlTag)
-#else
- HttpUtility.HtmlDecode(htmlTag)
-#endif
- );
+ MatchCollection matches = stripStyleAttributesRegex.Matches(htmlTag);
foreach (Match m in matches)
collection.attributes[m.Groups["name"].Value] = m.Groups["val"].Value;
diff --git a/test/HtmlToOpenXml.Tests/StyleTests.cs b/test/HtmlToOpenXml.Tests/StyleTests.cs
index 2fb56f5..24afe76 100644
--- a/test/HtmlToOpenXml.Tests/StyleTests.cs
+++ b/test/HtmlToOpenXml.Tests/StyleTests.cs
@@ -165,5 +165,21 @@ public void DuplicateStyle_ReturnsLatter()
var styleAttributes = HtmlAttributeCollection.ParseStyle("color:red;color:blue");
Assert.That(styleAttributes["color"], Is.EqualTo("blue"));
}
+
+ [Test(Description = "Encoded ':' and ';' characters are valid")]
+ public void EncodedStyle_ShouldSucceed()
+ {
+ var styleAttributes = HtmlAttributeCollection.ParseStyle("text-decoration:underline;color:red");
+ Assert.That(styleAttributes["text-decoration"], Is.EqualTo("underline"));
+ Assert.That(styleAttributes["color"], Is.EqualTo("red"));
+ }
+
+ [Test(Description = "Key style with no value should be ignored")]
+ public void EmptyStyle_ShouldBeIgnoredd()
+ {
+ var styleAttributes = HtmlAttributeCollection.ParseStyle("text-decoration;color:red");
+ Assert.That(styleAttributes["text-decoration"], Is.Null);
+ Assert.That(styleAttributes["color"], Is.EqualTo("red"));
+ }
}
}
From 32e95711cb03703b1fa49a285d8edff348831d86 Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Sun, 10 Nov 2024 19:06:32 +0100
Subject: [PATCH 05/13] Supports a feature to disable heading numbering #175
---
.../Expressions/HyperlinkExpression.cs | 2 +-
.../Numbering/HeadingElementExpression.cs | 4 +--
src/Html2OpenXml/HtmlConverter.cs | 33 +++++++++++++++++--
test/HtmlToOpenXml.Tests/HeadingTests.cs | 26 +++++++++++++++
test/HtmlToOpenXml.Tests/LinkTests.cs | 2 +-
5 files changed, 60 insertions(+), 7 deletions(-)
diff --git a/src/Html2OpenXml/Expressions/HyperlinkExpression.cs b/src/Html2OpenXml/Expressions/HyperlinkExpression.cs
index 46fdc9a..62221ec 100644
--- a/src/Html2OpenXml/Expressions/HyperlinkExpression.cs
+++ b/src/Html2OpenXml/Expressions/HyperlinkExpression.cs
@@ -113,7 +113,7 @@ public override IEnumerable Interpret (ParsingContext context)
h = new Hyperlink() { History = true, Anchor = "_top" };
}
// is it an anchor?
- else if (!context.Converter.ExcludeLinkAnchor && linkNode.Hash.Length > 1 && linkNode.Hash[0] == '#')
+ else if (context.Converter.SupportsAnchorLinks && linkNode.Hash.Length > 1 && linkNode.Hash[0] == '#')
{
h = new Hyperlink(
) { History = true, Anchor = linkNode.Hash.Substring(1) };
diff --git a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs
index 2c70032..9a9f6ff 100644
--- a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs
+++ b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs
@@ -40,9 +40,9 @@ public override IEnumerable Interpret (ParsingContext context)
paragraph.ParagraphProperties ??= new();
paragraph.ParagraphProperties.ParagraphStyleId =
context.DocumentStyle.GetParagraphStyle(context.DocumentStyle.DefaultStyles.HeadingStyle + level);
-
+
var runElement = childElements.FirstOrDefault();
- if (runElement != null && IsNumbering(runElement))
+ if (runElement != null && context.Converter.SupportsHeadingNumbering && IsNumbering(runElement))
{
var abstractNumId = GetOrCreateListTemplate(context, HeadingNumberingName);
var instanceId = GetListInstance(abstractNumId);
diff --git a/src/Html2OpenXml/HtmlConverter.cs b/src/Html2OpenXml/HtmlConverter.cs
index 7cb7a38..f834ecf 100755
--- a/src/Html2OpenXml/HtmlConverter.cs
+++ b/src/Html2OpenXml/HtmlConverter.cs
@@ -339,7 +339,8 @@ private TPart ResolveHeaderFooterPart(HeaderFooterValues? type)
public AcronymPosition AcronymPosition { get; set; }
///
- /// Gets or sets whether anchor links are included or not in the convertion.
+ /// Gets or sets whether anchor links are included or not in the conversion
+ /// (defaults ).
///
/// An anchor is a term used to define a hyperlink destination inside a document.
/// .
@@ -351,7 +352,23 @@ private TPart ResolveHeaderFooterPart(HeaderFooterValues? type)
/// elements
/// and set the value of href to #name of your bookmark.
///
- public bool ExcludeLinkAnchor { get; set; }
+ public bool SupportsAnchorLinks { get; set; } = true;
+
+ ///
+ /// Gets or sets whether anchor links are included or not in the conversion.
+ ///
+ /// An anchor is a term used to define a hyperlink destination inside a document.
+ /// .
+ ///
+ /// It exists some predefined anchors used by Word such as _top to refer to the top of the document.
+ /// The anchor #_top is always accepted regardless this property value.
+ /// For others anchors like refering to your own bookmark or a title, add a
+ /// and
+ /// elements
+ /// and set the value of href to #name of your bookmark.
+ ///
+ [Obsolete("Use SupportsAnchorLink instead, if ExcludeLinkAnchor = true -> SupportsAnchorLink = false")]
+ public bool ExcludeLinkAnchor { get => !SupportsAnchorLinks; set => SupportsAnchorLinks = !value; }
///
/// Gets the Html styles manager mapping to OpenXml style properties.
@@ -367,7 +384,7 @@ public WordDocumentStyle HtmlStyles
public CaptionPositionValues TableCaptionPosition { get; set; }
///
- /// Gets or sets whether the pre tag should be rendered as a table (default ).
+ /// Gets or sets whether the pre tag should be rendered as a table (defaults ).
///
/// The table will contains only one cell.
public bool RenderPreAsTable { get; set; }
@@ -378,6 +395,16 @@ public WordDocumentStyle HtmlStyles
///
public bool ContinueNumbering { get; set; } = true;
+ ///
+ /// Defines whether any headings (h1-h6) could be considered as multi-level numbering, such as
+ /// top-level headings (Heading 1) are numbered 1, 2, 3, for example, and second-level headings (Heading 2) are numbered 1.1, 1.2, 1.3.
+ /// This feature is enabled by default.
+ ///
+ /// The converter is detecting headings starting with a number (ie: 1. or 1 )
+ /// are considered as numbering.
+ ///
+ public bool SupportsHeadingNumbering { get; set; } = true;
+
///
/// Gets the mainDocumentPart of the destination OpenXml document.
///
diff --git a/test/HtmlToOpenXml.Tests/HeadingTests.cs b/test/HtmlToOpenXml.Tests/HeadingTests.cs
index c42ed25..b8feed1 100644
--- a/test/HtmlToOpenXml.Tests/HeadingTests.cs
+++ b/test/HtmlToOpenXml.Tests/HeadingTests.cs
@@ -51,6 +51,32 @@ public void OrderedPattern_ReturnsNumberingHeading(string html)
});
}
+ [TestCase("1. Heading 1
1.1 Heading Normal Case")]
+ [TestCase("1. Heading 1
1.1 Heading Double Space
", Description = "Double space after number")]
+ [TestCase("1. Heading 1
1.2 Heading Tab
", Description = "Tab after number")]
+ [TestCase("1. Heading 1
1.3Heading No Space
", Description = "No space after number")]
+ public void OrderedPattern_DisableNumberingSupports_ReturnsSimpleHeading(string html)
+ {
+ converter.SupportsHeadingNumbering = false;
+ var elements = converter.Parse(html);
+
+ var absNum = mainPart.NumberingDefinitionsPart?.Numbering
+ .Elements()
+ .Where(abs => abs.AbstractNumDefinitionName?.Val == NumberingExpressionBase.HeadingNumberingName)
+ .SingleOrDefault();
+ Assert.That(absNum, Is.Null);
+
+ var paragraphs = elements.Cast();
+ Assert.Multiple(() =>
+ {
+ Assert.That(paragraphs.Count(), Is.EqualTo(2));
+ Assert.That(paragraphs.First().InnerText, Is.EqualTo("1. Heading 1"));
+ Assert.That(paragraphs.First().ParagraphProperties?.NumberingProperties?.NumberingLevelReference?.Val,
+ Is.Null,
+ "First paragraph is not a numbering");
+ });
+ }
+
[Test]
public void MaxLevel_ShouldBeIgnored()
{
diff --git a/test/HtmlToOpenXml.Tests/LinkTests.cs b/test/HtmlToOpenXml.Tests/LinkTests.cs
index 27443ce..f688bef 100644
--- a/test/HtmlToOpenXml.Tests/LinkTests.cs
+++ b/test/HtmlToOpenXml.Tests/LinkTests.cs
@@ -82,7 +82,7 @@ public void Anchoring_WithUnknownTarget_ReturnsHyperlinkWithBookmark ()
[Test]
public void SetExcludeAnchoring_ReturnsSimpleRun ()
{
- converter.ExcludeLinkAnchor = true;
+ converter.SupportsAnchorLinks = false;
// _top is always present and bypass the previous rule
var elements = converter.Parse(@"Anchor2");
From bdb076d40d1cb48f7853cbd4ba957fd6e0098490 Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Sun, 10 Nov 2024 20:22:50 +0100
Subject: [PATCH 06/13] Improve nuget release notes and prepare next release
---
CHANGELOG.md | 8 ++++++++
src/Html2OpenXml/HtmlToOpenXml.csproj | 16 +++++++++++++---
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef44323..b4edec4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 3.2.2
+
+- Supports a feature to disable heading numbering #175
+- Support center image with margin auto #171
+- Support deprecrated align attribute for block #171
+- Fix parsing of style attribute with a key with no value
+- Improve parsing of style attribute to avoid an extra call to HtmlDecode
+
## 3.2.1
- Fix indentation of numbering list #166
diff --git a/src/Html2OpenXml/HtmlToOpenXml.csproj b/src/Html2OpenXml/HtmlToOpenXml.csproj
index 03daeff..bfffc34 100644
--- a/src/Html2OpenXml/HtmlToOpenXml.csproj
+++ b/src/Html2OpenXml/HtmlToOpenXml.csproj
@@ -9,13 +9,13 @@
HtmlToOpenXml
HtmlToOpenXml
HtmlToOpenXml.dll
- 3.2.1
+ 3.2.2
icon.png
Copyright 2009-$([System.DateTime]::Now.Year) Olivier Nizet
- See changelog https://github.com/onizet/html2openxml/blob/master/CHANGELOG.md
+ (Please write the package release notes in CHANGELOG.md)
README.md
office openxml netcore html
- 3.2.1
+ 3.2.2
MIT
https://github.com/onizet/html2openxml
https://github.com/onizet/html2openxml
@@ -64,5 +64,15 @@
true
+
+
+
+
+
+
+
+ @(ReleaseNoteLines, '%0a')
+
+
\ No newline at end of file
From 07fae6da38ff655044896a9358f384d23f8e789b Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Mon, 11 Nov 2024 15:32:23 +0100
Subject: [PATCH 07/13] Extend support of nested list for non-W3C compliant
html #173
---
CHANGELOG.md | 1 +
.../Expressions/Numbering/ListExpression.cs | 13 +++++-
test/HtmlToOpenXml.Tests/NumberingTests.cs | 42 ++++++++++++++++++-
3 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b4edec4..a6003e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
- Support deprecrated align attribute for block #171
- Fix parsing of style attribute with a key with no value
- Improve parsing of style attribute to avoid an extra call to HtmlDecode
+- Extend support of nested list for non-W3C compliant html #173
## 3.2.1
diff --git a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
index 811976c..ef7fa22 100644
--- a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
+++ b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
@@ -50,9 +50,20 @@ readonly struct ListContext(string listName, int absNumId, int instanceId, int l
public override IEnumerable Interpret(ParsingContext context)
{
- var liNodes = node.Children.Where(n => n.LocalName == "li");
+ var liNodes = node.Children.Where(n => n.LocalName.Equals("li", StringComparison.OrdinalIgnoreCase));
if (!liNodes.Any()) yield break;
+ // W3C requires that nested list stands below a `li` element but some editors
+ // don't care to respect the standard. Let's reparent those lists
+ var nestedList = node.Children.Where(n =>
+ n.LocalName.Equals("ol", StringComparison.OrdinalIgnoreCase) ||
+ n.LocalName.Equals("ul", StringComparison.OrdinalIgnoreCase));
+ if (nestedList.Any())
+ {
+ foreach (var list in nestedList)
+ list.PreviousElementSibling?.AppendChild(list);
+ }
+
var listContext = context.Properties("listContext");
var parentContext = listContext;
var listStyle = GetListName(node, listContext.Name);
diff --git a/test/HtmlToOpenXml.Tests/NumberingTests.cs b/test/HtmlToOpenXml.Tests/NumberingTests.cs
index a7b914e..17b75de 100644
--- a/test/HtmlToOpenXml.Tests/NumberingTests.cs
+++ b/test/HtmlToOpenXml.Tests/NumberingTests.cs
@@ -514,7 +514,7 @@ public void WithRtl_ReturnsBidi(string dir, bool? expectedValue)
}
[Test]
- public void NestedNumberList_ReturnsIncrementalIdentation()
+ public void NestedNumberList_ReturnsIncrementalIndentation()
{
const int maxLevel = 8;
var sb = new System.Text.StringBuilder();
@@ -541,5 +541,45 @@ public void NestedNumberList_ReturnsIncrementalIdentation()
TestContext.Out.WriteLine($"{i}. {ident?.Left?.Value}");
}
}
+
+ [Test(Description = "Nested list must be a children of a `li` tag but some editor are not respecting the W3C standard (issue #173)")]
+ public async Task NestedNumberList_NonCompliant_ReturnsIncrementalIndentation()
+ {
+ await converter.ParseBody(@"
+ - Item1
+ - Item2
+ - Item 2.1
+
");
+
+ var absNum = mainPart.NumberingDefinitionsPart?.Numbering
+ .Elements()
+ .SingleOrDefault();
+ Assert.That(absNum, Is.Not.Null);
+
+ var inst = mainPart.NumberingDefinitionsPart?.Numbering
+ .Elements().Where(i => i.AbstractNumId?.Val == absNum.AbstractNumberId)
+ .SingleOrDefault();
+ Assert.That(inst, Is.Not.Null);
+ Assert.That(inst.NumberID?.Value, Is.Not.Null);
+
+ var elements = mainPart.Document.Body!.ChildElements;
+ Assert.Multiple(() => {
+ Assert.That(elements, Has.Count.EqualTo(3));
+ Assert.That(elements, Is.All.TypeOf());
+ Assert.That(mainPart.NumberingDefinitionsPart?.Numbering, Is.Not.Null);
+ });
+
+ // assert paragraphs linked to numbering instance
+ Assert.Multiple(() =>
+ {
+ Assert.That(elements.Cast().Select(e =>
+ e.ParagraphProperties?.NumberingProperties?.NumberingId?.Val?.Value),
+ Has.All.EqualTo(inst.NumberID.Value),
+ "All paragraphs are linked to the same list instance");
+ Assert.That(elements.Take(2).Select(p => p.GetFirstChild()?.NumberingProperties?.NumberingLevelReference?.Val?.Value), Has.All.EqualTo(0));
+ Assert.That(elements.Last().GetFirstChild()?.NumberingProperties?.NumberingLevelReference?.Val?.Value, Is.EqualTo(1));
+ });
+ AssertThatOpenXmlDocumentIsValid();
+ }
}
}
\ No newline at end of file
From fed20dee0b5b35e69d8f880f37dd5ee3acc67ff2 Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Thu, 14 Nov 2024 16:21:12 +0100
Subject: [PATCH 08/13] Handle standalone paragraphs nested in list that must
be aligned with other list items #177
---
.../Expressions/Numbering/ListExpression.cs | 43 ++++++++++++++-----
test/HtmlToOpenXml.Tests/NumberingTests.cs | 30 +++++++++++++
2 files changed, 62 insertions(+), 11 deletions(-)
diff --git a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
index ef7fa22..3fa20af 100644
--- a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
+++ b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
@@ -90,17 +90,38 @@ public override IEnumerable Interpret(ParsingContext context)
var expression = new BlockElementExpression(liNode);
var childElements = expression.Interpret(context);
if (!childElements.Any()) continue;
- Paragraph p = (Paragraph) childElements.First();
-
- p.ParagraphProperties ??= new();
- p.ParagraphProperties.ParagraphStyleId = GetStyleIdForListItem(context.DocumentStyle, liNode);
- p.ParagraphProperties.NumberingProperties = new NumberingProperties {
- NumberingLevelReference = new() { Val = level - 1 },
- NumberingId = new() { Val = listContext.InstanceId }
- };
- if (listContext.Dir.HasValue) {
- p.ParagraphProperties.BiDi = new() {
- Val = OnOffValue.FromBoolean(listContext.Dir == DirectionMode.Rtl)
+
+ // ensure to filter out any non-paragraph like any nested table
+ var paragraphs = childElements.OfType();
+ var listItemStyleId = GetStyleIdForListItem(context.DocumentStyle, liNode);
+
+ if (paragraphs.Any())
+ {
+ var p = paragraphs.First();
+ p.ParagraphProperties ??= new();
+ p.ParagraphProperties.ParagraphStyleId = listItemStyleId;
+ p.ParagraphProperties!.NumberingProperties ??= new NumberingProperties {
+ NumberingLevelReference = new() { Val = level - 1 },
+ NumberingId = new() { Val = listContext.InstanceId }
+ };
+ if (listContext.Dir.HasValue) {
+ p.ParagraphProperties.BiDi = new() {
+ Val = OnOffValue.FromBoolean(listContext.Dir == DirectionMode.Rtl)
+ };
+ }
+ }
+
+ // any standalone paragraphs must be aligned (indented) along its current level
+ foreach (var p in paragraphs.Skip(1))
+ {
+ // if this is a list item paragraph, skip it
+ if (p.ParagraphProperties?.NumberingProperties is not null)
+ continue;
+
+ p.ParagraphProperties ??= new();
+ p.ParagraphProperties.ParagraphStyleId ??= (ParagraphStyleId?) listItemStyleId!.CloneNode(true);
+ p.ParagraphProperties.Indentation = new() {
+ Left = (level * Indentation * 2).ToString()
};
}
diff --git a/test/HtmlToOpenXml.Tests/NumberingTests.cs b/test/HtmlToOpenXml.Tests/NumberingTests.cs
index 17b75de..c48b699 100644
--- a/test/HtmlToOpenXml.Tests/NumberingTests.cs
+++ b/test/HtmlToOpenXml.Tests/NumberingTests.cs
@@ -581,5 +581,35 @@ await converter.ParseBody(@"
});
AssertThatOpenXmlDocumentIsValid();
}
+
+ [Test]
+ public void NestedParagraph_ReturnsIndentedItems()
+ {
+ var elements = converter.Parse(@"
+ -
+
Paragraph text
+ Paragraph text
+
+
");
+
+ Assert.That(elements, Is.Not.Empty);
+
+ var inst = mainPart.NumberingDefinitionsPart?.Numbering
+ .Elements()
+ .SingleOrDefault();
+ Assert.That(inst, Is.Not.Null);
+ Assert.Multiple(() => {
+ Assert.That(elements.Last().GetFirstChild()?.NumberingProperties?.NumberingId,
+ Is.Null,
+ "Last paragraph is standalone and not linked to a list instance");
+ Assert.That(elements.Cast().Select(e =>
+ e.ParagraphProperties?.ParagraphStyleId?.Val?.Value),
+ Has.All.EqualTo("ListParagraph"),
+ "All paragraphs use the same paragraph style");
+ Assert.That(elements.Last().GetFirstChild()?.Indentation?.Left?.Value,
+ Is.EqualTo("720"),
+ "Last standalone paragraph is aligned with the level 1");
+ });
+ }
}
}
\ No newline at end of file
From ef04a4e5d50bdeed243caf6aa323c118a3988309 Mon Sep 17 00:00:00 2001
From: Mo Ibrahim
Date: Mon, 2 Dec 2024 18:11:54 +0200
Subject: [PATCH 09/13] Fix: Apply 100 percentage widths to tables and
percentage widths cells when converting HTML to Word
---
HtmlToOpenXml.sln | 58 ++++----
examples/Demo/Program.cs | 2 +-
examples/Demo/Resources/CompleteRunTest.html | 134 +++++++++++-------
.../Expressions/Table/TableCellExpression.cs | 27 +++-
.../Expressions/Table/TableExpression.cs | 18 +--
5 files changed, 141 insertions(+), 98 deletions(-)
diff --git a/HtmlToOpenXml.sln b/HtmlToOpenXml.sln
index d702ded..2a20d0c 100644
--- a/HtmlToOpenXml.sln
+++ b/HtmlToOpenXml.sln
@@ -14,33 +14,33 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlToOpenXml.Tests", "test\HtmlToOpenXml.Tests\HtmlToOpenXml.Tests.csproj", "{CA0A68E0-45A0-4A01-A061-F951D93D6906}"
EndProject
Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {EF700F30-C9BB-49A6-912C-E3B77857B514}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EF700F30-C9BB-49A6-912C-E3B77857B514}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EF700F30-C9BB-49A6-912C-E3B77857B514}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EF700F30-C9BB-49A6-912C-E3B77857B514}.Release|Any CPU.Build.0 = Release|Any CPU
- {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F}.Release|Any CPU.Build.0 = Release|Any CPU
- {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {EF700F30-C9BB-49A6-912C-E3B77857B514} = {58520A98-BA53-4BA4-AAE3-786AA21331D6}
- {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F} = {84EA02ED-2E97-47D2-992E-32CC104A3A7A}
- {CA0A68E0-45A0-4A01-A061-F951D93D6906} = {84EA02ED-2E97-47D2-992E-32CC104A3A7A}
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {14EE1026-6507-4295-9FEE-67A55C3849CE}
- EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {EF700F30-C9BB-49A6-912C-E3B77857B514}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EF700F30-C9BB-49A6-912C-E3B77857B514}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EF700F30-C9BB-49A6-912C-E3B77857B514}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EF700F30-C9BB-49A6-912C-E3B77857B514}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {EF700F30-C9BB-49A6-912C-E3B77857B514} = {58520A98-BA53-4BA4-AAE3-786AA21331D6}
+ {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F} = {84EA02ED-2E97-47D2-992E-32CC104A3A7A}
+ {CA0A68E0-45A0-4A01-A061-F951D93D6906} = {84EA02ED-2E97-47D2-992E-32CC104A3A7A}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {14EE1026-6507-4295-9FEE-67A55C3849CE}
+ EndGlobalSection
EndGlobal
diff --git a/examples/Demo/Program.cs b/examples/Demo/Program.cs
index 0620d54..e794af4 100644
--- a/examples/Demo/Program.cs
+++ b/examples/Demo/Program.cs
@@ -74,4 +74,4 @@ static void AssertThatOpenXmlDocumentIsValid(WordprocessingDocument wpDoc)
Console.ReadLine();
}
}
-}
\ No newline at end of file
+}
diff --git a/examples/Demo/Resources/CompleteRunTest.html b/examples/Demo/Resources/CompleteRunTest.html
index 0976ee1..9c98726 100644
--- a/examples/Demo/Resources/CompleteRunTest.html
+++ b/examples/Demo/Resources/CompleteRunTest.html
@@ -4,6 +4,25 @@
+
+
+
+ Column 1 |
+ Column 2 |
+ Column 3 |
+
+
+ Row 1, Cell 1 |
+ Row 1, Cell 2 |
+ Row 1, Cell 3 |
+
+
+ Row 2, Cell 1 |
+ Row 2, Cell 2 |
+ Row 2, Cell 3 |
+
+
+
Heading 1
Heading 2
@@ -15,8 +34,11 @@ Heading 5
Small caps
Strike Line Through Overline Underline
Bold
- This is a bold
- text
+
+ This is a
+ bold
+ text
+
Bold
Bolder
Lighter
@@ -47,7 +69,8 @@ Heading 5
- Heading 5
OfDEXhz/AIRbxtAkV1pYNrJHNC0qSbPlDKQDg8e3tVD4Q6BKPGmp67Y2lxbaJ5ckVo04IMgZ
1KjnqAByfXFezMiv95Q2PUZoCKOigY9BSkA9QDjmgqGBDAEHsaia0tnQxtbxMjdVKAg0W9pb
Wilba3ihB6iNAufyoltLaZw8tvFIw6FkBNSgADA4FLRRRRRRRX//2Q==
- ">
+ ">
+
@@ -102,79 +126,81 @@ Heading 5
-
-For 50 years, WWF has been protecting the future of nature. The world's leading conservation organization, WWF works in 100 countries and is supported by 1.2 million members in the United States and close to 5 million globally.
-
+
+ For 50 years, WWF has been protecting the future of nature. The world's leading conservation organization, WWF works in 100 countries and is supported by 1.2 million members in the United States and close to 5 million globally.
+
-
My Text
+
My Text
-An ordered list:
+ An ordered list:
- - Coffee
- - Tea
- - Milk
-
- - Coffee
- - Tea
-
- - Earl Grey
- - Green
- - Rosboh
-
-
- - Milk
-
-
- - Wine
+ - Coffee
+ - Tea
+ -
+ Milk
+
+ - Coffee
+ -
+ Tea
+
+ - Earl Grey
+ - Green
+ - Rosboh
+
+
+ - Milk
+
+
+ - Wine
-
-
- delta parameter (d)
- Looks how cool is Open Xml.
-
- Now with HtmlToOpenXml, it never been so easy to convert html.
-
- If you like it, add me a rating on github
-
-
- simple text
-
- Hello !
- je suis du texte
-
écrit en oblique.
-
-
public void SetContentType(System.Web.HttpRequest request, System.Web.HttpResponse response, String reportName)
+
+
+
delta parameter (d)
+ Looks how cool is
Open Xml.
+
+ Now with
HtmlToOpenXml, it never been so easy to convert html.
+
+ If you like it, add me a rating on github
+
+
+ simple text
+
+ Hello !
+ je suis du texte
+
écrit en oblique.
+
+
public void SetContentType(System.Web.HttpRequest request, System.Web.HttpResponse response, String reportName)
{
if (request.Browser.Browser.Contains("IE"))
{
- // Replace the %20 to obtain a clean name when saving the file from Word.
+ // Replace the %20 to obtain a clean name when saving the file from Word.
encodedFilename =
Uri.EscapeDataString(Path.GetFileNameWithoutExtension(encodedFilename)).Replace("%20", " ")
+ Path.GetExtension(encodedFilename);
}
}
-
-
+
+
Some <Pre> starting one
line below!
-
-
Header placeholder:
-
- - Item 1
- - Item 2
-
-
Footer Placeholder
-
+
+
Header placeholder:
+
+ - Item 1
+ - Item 2
+
+
Footer Placeholder
+
Lorem Ipsum
-
diff --git a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs
index 23bd2e2..7f2141d 100644
--- a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs
+++ b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs
@@ -1,4 +1,4 @@
-/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved
+/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved
*
* This source is subject to the Microsoft Permissive License.
* Please see the License.txt file for more information.
@@ -10,6 +10,7 @@
* PARTICULAR PURPOSE.
*/
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using AngleSharp.Html.Dom;
using DocumentFormat.OpenXml;
@@ -59,6 +60,28 @@ protected override void ComposeStyles(ParsingContext context)
{
base.ComposeStyles(context);
+ Unit width = styleAttributes.GetUnit("width");
+
+ if (!width.IsValid)
+ {
+ var widthValue = node.GetAttribute("width");
+ if (!string.IsNullOrEmpty(widthValue))
+ {
+ width = Unit.Parse(widthValue);
+ }
+ }
+
+ if (width.IsValid)
+ {
+ cellProperties.TableCellWidth = new TableCellWidth
+ {
+ Type = width.Type == UnitMetric.Percent ? TableWidthUnitValues.Pct : TableWidthUnitValues.Dxa,
+ Width = width.Type == UnitMetric.Percent
+ ? ((int) (width.Value * 50)).ToString(CultureInfo.InvariantCulture)
+ : width.ValueInDxa.ToString(CultureInfo.InvariantCulture)
+ };
+ }
+
// Manage vertical text (only for table cell)
string? direction = styleAttributes!["writing-mode"];
if (direction != null)
@@ -98,4 +121,4 @@ internal static bool IsValidRowSpan(int rowSpan)
// 0 means it extends until the end of the table grouping section
return rowSpan == 0 || rowSpan > 1;
}
-}
\ No newline at end of file
+}
diff --git a/src/Html2OpenXml/Expressions/Table/TableExpression.cs b/src/Html2OpenXml/Expressions/Table/TableExpression.cs
index ecb0b9c..84c1d02 100644
--- a/src/Html2OpenXml/Expressions/Table/TableExpression.cs
+++ b/src/Html2OpenXml/Expressions/Table/TableExpression.cs
@@ -1,4 +1,4 @@
-/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved
+/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved
*
* This source is subject to the Microsoft Permissive License.
* Please see the License.txt file for more information.
@@ -175,17 +175,11 @@ protected override void ComposeStyles (ParsingContext context)
switch (width.Type)
{
case UnitMetric.Percent:
- if (width.Value == 100)
+ tableProperties.TableWidth = new TableWidth
{
- // Use Auto=0 instead of Pct=auto
- // bug reported by scarhand (https://html2openxml.codeplex.com/workitem/12494)
- tableProperties.TableWidth = new() { Type = TableWidthUnitValues.Auto, Width = "0" };
- }
- else
- {
- tableProperties.TableWidth = new() { Type = TableWidthUnitValues.Pct,
- Width = (width.Value * 50).ToString(CultureInfo.InvariantCulture) };
- }
+ Type = TableWidthUnitValues.Pct,
+ Width = (width.Value * 50).ToString(CultureInfo.InvariantCulture)
+ };
break;
case UnitMetric.Point:
case UnitMetric.Pixel:
@@ -287,4 +281,4 @@ protected override void ComposeStyles (ParsingContext context)
}
}
}
-}
\ No newline at end of file
+}
From aec86c6ab8d8269c47cc644a761c346358750bf9 Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Mon, 2 Dec 2024 21:42:30 +0100
Subject: [PATCH 10/13] Trigger pipeline for pull requests
---
.github/workflows/dotnet.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index eae4590..593fcf8 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -10,7 +10,6 @@ on:
- 'docs/**'
- '**/*.md'
pull_request:
- branches: [ "dev" ]
jobs:
net8:
From b05565254a011a00f0de050d96678653a89ed56f Mon Sep 17 00:00:00 2001
From: Mo Ibrahim
Date: Tue, 3 Dec 2024 10:08:32 +0200
Subject: [PATCH 11/13] Fix: Apply comments
---
src/Html2OpenXml/Expressions/Table/TableCellExpression.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs
index 7f2141d..00d67f7 100644
--- a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs
+++ b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs
@@ -60,11 +60,11 @@ protected override void ComposeStyles(ParsingContext context)
{
base.ComposeStyles(context);
- Unit width = styleAttributes.GetUnit("width");
+ Unit width = styleAttributes!.GetUnit("width");
if (!width.IsValid)
{
- var widthValue = node.GetAttribute("width");
+ var widthValue = this.node.GetAttribute("width");
if (!string.IsNullOrEmpty(widthValue))
{
width = Unit.Parse(widthValue);
From 48af83381dedad9393278a9851e3543a06713095 Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Wed, 11 Dec 2024 22:40:29 +0100
Subject: [PATCH 12/13] Update changelog with PR180
---
CHANGELOG.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a6003e6..bba08de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,8 @@
- Fix parsing of style attribute with a key with no value
- Improve parsing of style attribute to avoid an extra call to HtmlDecode
- Extend support of nested list for non-W3C compliant html #173
+- Change way to apply table 100% width
+- Allow to apply percentage widths cells
## 3.2.1
From 5c6bfe21a1f6bdae2d3d9fa52b783a8dbc45b609 Mon Sep 17 00:00:00 2001
From: Olivier Nizet
Date: Wed, 11 Dec 2024 22:40:45 +0100
Subject: [PATCH 13/13] Remove disambiguation on code
---
src/Html2OpenXml/Expressions/Table/TableCellExpression.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs
index 00d67f7..4e816f8 100644
--- a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs
+++ b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs
@@ -61,10 +61,9 @@ protected override void ComposeStyles(ParsingContext context)
base.ComposeStyles(context);
Unit width = styleAttributes!.GetUnit("width");
-
if (!width.IsValid)
{
- var widthValue = this.node.GetAttribute("width");
+ var widthValue = cellNode.GetAttribute("width");
if (!string.IsNullOrEmpty(widthValue))
{
width = Unit.Parse(widthValue);