From a6c3546ef893479225961b1576dfd71cff3a9c15 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Wed, 26 Nov 2025 23:53:40 +0100 Subject: [PATCH 1/3] Further optimisation to generalise the usage of ReadOnlySpan and short-cicruit in complex GetStyle attributes. --- .../Collections/HtmlAttributeCollection.cs | 30 ++++++++++++++++-- .../Expressions/BlockElementExpression.cs | 8 ++--- .../Expressions/BodyExpression.cs | 7 +++-- .../Expressions/Numbering/ListExpression.cs | 8 ++--- .../Table/TableCaptionExpression.cs | 5 +-- .../Expressions/Table/TableCellExpression.cs | 31 +++++++++---------- .../Expressions/Table/TableColExpression.cs | 2 +- .../Table/TableElementExpressionBase.cs | 2 +- .../Expressions/Table/TableRowExpression.cs | 2 +- .../Primitives/HtmlColor.Named.cs | 1 - .../Utilities/AngleSharpExtensions.cs | 8 +++-- src/Html2OpenXml/Utilities/Converter.cs | 24 ++++++-------- .../Primitives/StyleParserTests.cs | 13 ++++---- test/HtmlToOpenXml.Tests/StyleTests.cs | 10 +++--- 14 files changed, 86 insertions(+), 65 deletions(-) diff --git a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs index 1ea4cc03..0f0aacb0 100755 --- a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs +++ b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs @@ -107,16 +107,34 @@ public static HtmlAttributeCollection ParseStyle(string? htmlStyles) /// /// Gets the named attribute. /// - public string? this[string name] + public ReadOnlySpan this[string name] { get { if (attributes.TryGetValue(name, out var range)) - return rawValue.AsSpan().Slice(range).ToString().Trim(); - return null; + return rawValue.AsSpan().Slice(range).Trim(); + return []; } } + /// + /// Determines whether the collection contains the specified key. + /// + public bool ContainsKey(string name) + { + return attributes.ContainsKey(name); + } + + /// + /// Efficient way to determine if a style is equals to a value. + /// + public bool HasKeyEqualsTo(string name, ReadOnlySpan value) + { + if (attributes.TryGetValue(name, out var range)) + return rawValue.AsSpan().Slice(range).Trim().Equals(value, StringComparison.InvariantCultureIgnoreCase); + return false; + } + /// /// Gets an attribute representing a color (named color, hexadecimal or hexadecimal /// without the preceding # character). @@ -147,6 +165,8 @@ public Unit GetUnit(string name, UnitMetric defaultMetric = UnitMetric.Unitless) public Margin GetMargin(string name) { Margin margin = Margin.Empty; + if (IsEmpty) return margin; + if (attributes.TryGetValue(name, out var range)) margin = Margin.Parse(rawValue.AsSpan().Slice(range)); @@ -194,6 +214,8 @@ public HtmlBorder GetBorders() public SideBorder GetSideBorder(string name) { SideBorder border = SideBorder.Empty; + if (IsEmpty) return border; + if (attributes.TryGetValue(name, out Range range)) border = SideBorder.Parse(rawValue.AsSpan().Slice(range)); @@ -224,6 +246,8 @@ public SideBorder GetSideBorder(string name) public HtmlFont GetFont(string name) { HtmlFont font = HtmlFont.Empty; + if (IsEmpty) return font; + if (attributes.TryGetValue(name, out Range range)) font = HtmlFont.Parse(rawValue.AsSpan().Slice(range)); diff --git a/src/Html2OpenXml/Expressions/BlockElementExpression.cs b/src/Html2OpenXml/Expressions/BlockElementExpression.cs index bf5de423..54eb692c 100644 --- a/src/Html2OpenXml/Expressions/BlockElementExpression.cs +++ b/src/Html2OpenXml/Expressions/BlockElementExpression.cs @@ -90,7 +90,7 @@ protected override IEnumerable Interpret ( { return ComposeChildren(context, childNodes, paraProperties, (runs) => { - if ("always".Equals(styleAttributes!["page-break-before"], StringComparison.OrdinalIgnoreCase)) + if (styleAttributes.HasKeyEqualsTo("page-break-before", "always")) { runs.Add( new Run( @@ -102,7 +102,7 @@ protected override IEnumerable Interpret ( } }, (runs) => { - if ("always".Equals(styleAttributes!["page-break-after"], StringComparison.OrdinalIgnoreCase)) + if (styleAttributes.HasKeyEqualsTo("page-break-after", "always")) { runs.Add(new Run( new Break() { Type = BreakValues.Page })); @@ -186,7 +186,7 @@ protected override void ComposeStyles (ParsingContext context) }; } - JustificationValues? align = Converter.ToParagraphAlign(styleAttributes!["text-align"]); + JustificationValues? align = Converter.ToParagraphAlign(styleAttributes["text-align"]); if (!align.HasValue) align = Converter.ToParagraphAlign(node.GetAttribute("align")); if (!align.HasValue) align = Converter.ToParagraphAlign(styleAttributes["justify-content"]); if (align.HasValue) @@ -256,7 +256,7 @@ protected override void ComposeStyles (ParsingContext context) var lineHeight = styleAttributes.GetUnit("line-height"); if (!lineHeight.IsValid - && "normal".Equals(styleAttributes["line-height"], StringComparison.OrdinalIgnoreCase)) + && styleAttributes.HasKeyEqualsTo("line-height", "normal")) { // if `normal` is specified, reset any values lineHeight = new Unit(UnitMetric.Unitless, 1); diff --git a/src/Html2OpenXml/Expressions/BodyExpression.cs b/src/Html2OpenXml/Expressions/BodyExpression.cs index 462d375d..9b86a3a4 100644 --- a/src/Html2OpenXml/Expressions/BodyExpression.cs +++ b/src/Html2OpenXml/Expressions/BodyExpression.cs @@ -69,10 +69,11 @@ protected override void ComposeStyles(ParsingContext context) // Unsupported W3C attribute but claimed by users. Specified at level, the page // orientation is applied on the whole document - string? attr = styleAttributes!["page-orientation"]; - if (attr != null) + if (styleAttributes.ContainsKey("page-orientation")) { - PageOrientationValues orientation = Converter.ToPageOrientation(attr); + PageOrientationValues orientation = PageOrientationValues.Portrait; + if (styleAttributes.HasKeyEqualsTo("page-orientation", "landscape")) + orientation = PageOrientationValues.Landscape; var sectionProperties = mainPart.Document.Body!.GetFirstChild(); if (sectionProperties == null || sectionProperties.GetFirstChild() == null) diff --git a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs index 2d071b43..a2a14798 100644 --- a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs +++ b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs @@ -214,14 +214,14 @@ private static string GetListName(IElement listNode, string? parentName = null) { var styleAttributes = listNode.GetStyles(); bool orderedList = listNode.NodeName.Equals("ol", StringComparison.OrdinalIgnoreCase); - string? type = styleAttributes["list-style-type"]; + var type = styleAttributes["list-style-type"]; - if(orderedList && string.IsNullOrEmpty(type)) + if(orderedList && type.IsEmpty) { type = ListTypeToListStyleType(listNode.GetAttribute("type")); } - if (string.IsNullOrEmpty(type) || !supportedListTypes.Contains(type!)) + if (type.IsEmpty || !supportedListTypes.Contains(type.ToString())) { if (parentName != null && IsCascadingStyle(parentName)) return parentName!; @@ -229,7 +229,7 @@ private static string GetListName(IElement listNode, string? parentName = null) type = orderedList? "decimal" : "disc"; } - return type!; + return type.ToString(); } /// diff --git a/src/Html2OpenXml/Expressions/Table/TableCaptionExpression.cs b/src/Html2OpenXml/Expressions/Table/TableCaptionExpression.cs index 8a05e34e..2c7e3346 100644 --- a/src/Html2OpenXml/Expressions/Table/TableCaptionExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableCaptionExpression.cs @@ -54,8 +54,9 @@ public override IEnumerable Interpret (ParsingContext context) } p.Append(childElements); - string? att = styleAttributes!["text-align"] ?? node.GetAttribute("align"); - if (!string.IsNullOrEmpty(att)) + var att = styleAttributes["text-align"]; + if (att.IsEmpty) att = node.GetAttribute("align"); + if (!att.IsEmpty) { JustificationValues? align = Converter.ToParagraphAlign(att); if (align.HasValue) diff --git a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs index 6a4f94cb..0cf036ec 100644 --- a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs @@ -62,7 +62,7 @@ protected override void ComposeStyles(ParsingContext context) { base.ComposeStyles(context); - Unit width = styleAttributes!.GetUnit("width"); + Unit width = styleAttributes.GetUnit("width"); if (!width.IsValid) { var widthValue = cellNode.GetAttribute("width"); @@ -84,23 +84,22 @@ protected override void ComposeStyles(ParsingContext context) } // Manage vertical text (only for table cell) - string? direction = styleAttributes!["writing-mode"]; - if (direction != null) + var direction = styleAttributes["writing-mode"]; + if (!direction.IsEmpty) { - switch (direction) + if (direction.Equals("tb-lr", StringComparison.InvariantCultureIgnoreCase) || + direction.Equals("vertical-lr", StringComparison.InvariantCultureIgnoreCase)) { - case "tb-lr": - case "vertical-lr": - cellProperties.TextDirection = new() { Val = TextDirectionValues.BottomToTopLeftToRight }; - cellProperties.TableCellVerticalAlignment = new() { Val = TableVerticalAlignmentValues.Center }; - paraProperties.Justification = new() { Val = JustificationValues.Center }; - break; - case "tb-rl": - case "vertical-rl": - cellProperties.TextDirection = new() { Val = TextDirectionValues.TopToBottomRightToLeft }; - cellProperties.TableCellVerticalAlignment = new() { Val = TableVerticalAlignmentValues.Center }; - paraProperties.Justification = new() { Val = JustificationValues.Center }; - break; + cellProperties.TextDirection = new() { Val = TextDirectionValues.BottomToTopLeftToRight }; + cellProperties.TableCellVerticalAlignment = new() { Val = TableVerticalAlignmentValues.Center }; + paraProperties.Justification = new() { Val = JustificationValues.Center }; + } + else if (direction.Equals("tb-rl", StringComparison.InvariantCultureIgnoreCase) || + direction.Equals("vertical-rl", StringComparison.InvariantCultureIgnoreCase)) + { + cellProperties.TextDirection = new() { Val = TextDirectionValues.TopToBottomRightToLeft }; + cellProperties.TableCellVerticalAlignment = new() { Val = TableVerticalAlignmentValues.Center }; + paraProperties.Justification = new() { Val = JustificationValues.Center }; } } } diff --git a/src/Html2OpenXml/Expressions/Table/TableColExpression.cs b/src/Html2OpenXml/Expressions/Table/TableColExpression.cs index c51269de..6edf0d1b 100644 --- a/src/Html2OpenXml/Expressions/Table/TableColExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableColExpression.cs @@ -35,7 +35,7 @@ public override IEnumerable Interpret(ParsingContext context) ComposeStyles(context); var column = new GridColumn(); - var width = styleAttributes!.GetUnit("width"); + var width = styleAttributes.GetUnit("width"); if (width.IsValid) { if (width.IsFixed) diff --git a/src/Html2OpenXml/Expressions/Table/TableElementExpressionBase.cs b/src/Html2OpenXml/Expressions/Table/TableElementExpressionBase.cs index 27bef6f4..a90e8382 100644 --- a/src/Html2OpenXml/Expressions/Table/TableElementExpressionBase.cs +++ b/src/Html2OpenXml/Expressions/Table/TableElementExpressionBase.cs @@ -71,7 +71,7 @@ protected override void ComposeStyles(ParsingContext context) { base.ComposeStyles(context); - var valign = Converter.ToVAlign(styleAttributes!["vertical-align"]); + var valign = Converter.ToVAlign(styleAttributes["vertical-align"]); if (!valign.HasValue) valign = Converter.ToVAlign(node.GetAttribute("valign")); if (!valign.HasValue) { diff --git a/src/Html2OpenXml/Expressions/Table/TableRowExpression.cs b/src/Html2OpenXml/Expressions/Table/TableRowExpression.cs index 25c7ce1d..8b1223b9 100644 --- a/src/Html2OpenXml/Expressions/Table/TableRowExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableRowExpression.cs @@ -101,7 +101,7 @@ protected override void ComposeStyles(ParsingContext context) { base.ComposeStyles(context); - Unit unit = styleAttributes!.GetUnit("height", UnitMetric.Pixel); + Unit unit = styleAttributes.GetUnit("height", UnitMetric.Pixel); if (!unit.IsValid) unit = Unit.Parse(rowNode.GetAttribute("height").AsSpan(), UnitMetric.Pixel); switch (unit.Metric) diff --git a/src/Html2OpenXml/Primitives/HtmlColor.Named.cs b/src/Html2OpenXml/Primitives/HtmlColor.Named.cs index b8301893..400463db 100755 --- a/src/Html2OpenXml/Primitives/HtmlColor.Named.cs +++ b/src/Html2OpenXml/Primitives/HtmlColor.Named.cs @@ -15,7 +15,6 @@ private static HtmlColor GetNamedColor (ReadOnlySpan name) { // the longest built-in Color's name is much lower than this check, so we should not allocate here in a typical usage Span loweredValue = name.Length <= 128 ? stackalloc char[name.Length] : new char[name.Length]; - name.ToLowerInvariant(loweredValue); namedColors.TryGetValue(loweredValue.ToString(), out var color); diff --git a/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs b/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs index 4caed8b9..21cb8e96 100644 --- a/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs +++ b/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs @@ -156,9 +156,11 @@ 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, string defaultLayout) + public static bool IsInlineLayout(ReadOnlySpan displayMode, string defaultLayout) { - return (displayMode ?? defaultLayout) - .StartsWith("inline", StringComparison.OrdinalIgnoreCase) == true; + if (displayMode.IsEmpty) + displayMode = defaultLayout.AsSpan(); + + return displayMode.StartsWith("inline", StringComparison.InvariantCultureIgnoreCase); } } \ No newline at end of file diff --git a/src/Html2OpenXml/Utilities/Converter.cs b/src/Html2OpenXml/Utilities/Converter.cs index 9d5907d2..4d2290c1 100755 --- a/src/Html2OpenXml/Utilities/Converter.cs +++ b/src/Html2OpenXml/Utilities/Converter.cs @@ -22,12 +22,13 @@ static class Converter /// /// Convert the Html text align attribute (horizontal alignement) to its corresponding OpenXml value. /// - public static JustificationValues? ToParagraphAlign(string? htmlAlign) + public static JustificationValues? ToParagraphAlign(ReadOnlySpan span) { - if (htmlAlign == null) return null; - return htmlAlign.ToLowerInvariant() switch + Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; + span.ToLowerInvariant(loweredValue); + return loweredValue switch { - "left" => JustificationValues.Left, + "left" => JustificationValues.Left, "right" => JustificationValues.Right, "center" => JustificationValues.Center, "justify" => JustificationValues.Both, @@ -38,10 +39,11 @@ static class Converter /// /// Convert the Html vertical-align attribute to its corresponding OpenXml value. /// - public static TableVerticalAlignmentValues? ToVAlign(string? htmlAlign) + public static TableVerticalAlignmentValues? ToVAlign(ReadOnlySpan span) { - if (htmlAlign == null) return null; - return htmlAlign.ToLowerInvariant() switch + Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; + span.ToLowerInvariant(loweredValue); + return loweredValue switch { "top" => TableVerticalAlignmentValues.Top, "middle" => TableVerticalAlignmentValues.Center, @@ -159,14 +161,6 @@ public static BorderValues ToBorderStyle(ReadOnlySpan span) }; } - public static PageOrientationValues ToPageOrientation(string? orientation) - { - if ( "landscape".Equals(orientation,StringComparison.OrdinalIgnoreCase)) - return PageOrientationValues.Landscape; - - return PageOrientationValues.Portrait; - } - public static ICollection ToTextDecoration(ReadOnlySpan values) { // this style could take multiple values separated by a space diff --git a/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs index 73f02e82..ebdce137 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs @@ -9,21 +9,22 @@ namespace HtmlToOpenXml.Tests.Primitives public class StyleParserTests { [TestCase("text-decoration:underline; color: red ")] - [TestCase("text-decoration:underline;color:red")] + [TestCase("text-decoration : underline ;color :red")] public void ParseStyle_ShouldSucceed(string htmlStyle) { var styles = HtmlAttributeCollection.ParseStyle(htmlStyle); Assert.Multiple(() => { - Assert.That(styles["text-decoration"], Is.EqualTo("underline")); - Assert.That(styles["color"], Is.EqualTo("red")); + Assert.That(styles.HasKeyEqualsTo("text-decoration", "underline"), Is.True); + Assert.That(styles.HasKeyEqualsTo("color", "red"), Is.True); + Assert.That(styles["color"].ToString(), Is.EqualTo("red")); }); } [Test(Description = "Parser should consider the last occurence of a style")] public void DuplicateStyle_ReturnsLatter() { - var styleAttributes = HtmlAttributeCollection.ParseStyle("color:red;color:blue"); - Assert.That(styleAttributes["color"], Is.EqualTo("blue")); + var styleAttributes = HtmlAttributeCollection.ParseStyle("color:red;color:BLUE"); + Assert.That(styleAttributes.HasKeyEqualsTo("color", "blue"), Is.True); } [TestCase("color;color;")] @@ -33,7 +34,7 @@ public void InvalidStyle_ShouldBeEmpty(string htmlStyle) { var styles = HtmlAttributeCollection.ParseStyle(htmlStyle); Assert.That(styles.IsEmpty, Is.True); - Assert.That(styles["color"], Is.Null); + Assert.That(styles.ContainsKey("color"), Is.False); } [Test] diff --git a/test/HtmlToOpenXml.Tests/StyleTests.cs b/test/HtmlToOpenXml.Tests/StyleTests.cs index 855b071c..61b1d0fd 100644 --- a/test/HtmlToOpenXml.Tests/StyleTests.cs +++ b/test/HtmlToOpenXml.Tests/StyleTests.cs @@ -163,23 +163,23 @@ public void ManualAddStyle_ThenRefreshStyles_ShouldSucceed() public void DuplicateStyle_ReturnsLatter() { var styleAttributes = HtmlAttributeCollection.ParseStyle("color:red;color:blue"); - Assert.That(styleAttributes["color"], Is.EqualTo("blue")); + Assert.That(styleAttributes["color"].ToString(), 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")); + Assert.That(styleAttributes["text-decoration"].ToString(), Is.EqualTo("underline")); + Assert.That(styleAttributes["color"].ToString(), Is.EqualTo("red")); } [Test(Description = "Key style with no value should be ignored")] public void EmptyStyle_ShouldBeIgnored() { var styleAttributes = HtmlAttributeCollection.ParseStyle("text-decoration;color:red"); - Assert.That(styleAttributes["text-decoration"], Is.Null); - Assert.That(styleAttributes["color"], Is.EqualTo("red")); + Assert.That(styleAttributes.ContainsKey("text-decoration"), Is.False); + Assert.That(styleAttributes["color"].ToString(), Is.EqualTo("red")); } } } From 731e44ffe0bca38b4e0f748a49d906e0ce8ce2a4 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Thu, 27 Nov 2025 00:05:50 +0100 Subject: [PATCH 2/3] Deal with net462 and the not implicit cast to Span --- src/Html2OpenXml/Collections/HtmlAttributeCollection.cs | 7 +++++-- src/Html2OpenXml/Expressions/Numbering/ListExpression.cs | 8 ++++---- src/Html2OpenXml/Utilities/AngleSharpExtensions.cs | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs index 0f0aacb0..f1492673 100755 --- a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs +++ b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs @@ -128,10 +128,13 @@ public bool ContainsKey(string name) /// /// Efficient way to determine if a style is equals to a value. /// - public bool HasKeyEqualsTo(string name, ReadOnlySpan value) + public bool HasKeyEqualsTo(string name, string value) { if (attributes.TryGetValue(name, out var range)) - return rawValue.AsSpan().Slice(range).Trim().Equals(value, StringComparison.InvariantCultureIgnoreCase); + { + var span = rawValue.AsSpan().Slice(range).Trim(); + return span.Equals(value.AsSpan(), StringComparison.InvariantCultureIgnoreCase); + } return false; } diff --git a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs index a2a14798..548ed09f 100644 --- a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs +++ b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs @@ -214,14 +214,14 @@ private static string GetListName(IElement listNode, string? parentName = null) { var styleAttributes = listNode.GetStyles(); bool orderedList = listNode.NodeName.Equals("ol", StringComparison.OrdinalIgnoreCase); - var type = styleAttributes["list-style-type"]; + string? type = styleAttributes["list-style-type"].ToString(); - if(orderedList && type.IsEmpty) + if(orderedList && string.IsNullOrEmpty(type)) { type = ListTypeToListStyleType(listNode.GetAttribute("type")); } - if (type.IsEmpty || !supportedListTypes.Contains(type.ToString())) + if (string.IsNullOrEmpty(type) || !supportedListTypes.Contains(type!)) { if (parentName != null && IsCascadingStyle(parentName)) return parentName!; @@ -229,7 +229,7 @@ private static string GetListName(IElement listNode, string? parentName = null) type = orderedList? "decimal" : "disc"; } - return type.ToString(); + return type!; } /// diff --git a/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs b/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs index 21cb8e96..31763e87 100644 --- a/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs +++ b/src/Html2OpenXml/Utilities/AngleSharpExtensions.cs @@ -161,6 +161,6 @@ public static bool IsInlineLayout(ReadOnlySpan displayMode, string default if (displayMode.IsEmpty) displayMode = defaultLayout.AsSpan(); - return displayMode.StartsWith("inline", StringComparison.InvariantCultureIgnoreCase); + return displayMode.StartsWith("inline".AsSpan(), StringComparison.InvariantCultureIgnoreCase); } } \ No newline at end of file From 8532595da20c8a12b053fe39fb94d3240ddf9d1e Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Thu, 27 Nov 2025 00:12:25 +0100 Subject: [PATCH 3/3] More implicit cast --- src/Html2OpenXml/Expressions/BlockElementExpression.cs | 2 +- .../Expressions/Table/TableCaptionExpression.cs | 2 +- src/Html2OpenXml/Expressions/Table/TableCellExpression.cs | 8 ++++---- .../Expressions/Table/TableElementExpressionBase.cs | 4 ++-- src/Html2OpenXml/Expressions/Table/TableExpression.cs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Html2OpenXml/Expressions/BlockElementExpression.cs b/src/Html2OpenXml/Expressions/BlockElementExpression.cs index 54eb692c..79731535 100644 --- a/src/Html2OpenXml/Expressions/BlockElementExpression.cs +++ b/src/Html2OpenXml/Expressions/BlockElementExpression.cs @@ -187,7 +187,7 @@ protected override void ComposeStyles (ParsingContext context) } JustificationValues? align = Converter.ToParagraphAlign(styleAttributes["text-align"]); - if (!align.HasValue) align = Converter.ToParagraphAlign(node.GetAttribute("align")); + if (!align.HasValue) align = Converter.ToParagraphAlign(node.GetAttribute("align").AsSpan()); if (!align.HasValue) align = Converter.ToParagraphAlign(styleAttributes["justify-content"]); if (align.HasValue) { diff --git a/src/Html2OpenXml/Expressions/Table/TableCaptionExpression.cs b/src/Html2OpenXml/Expressions/Table/TableCaptionExpression.cs index 2c7e3346..509be4c2 100644 --- a/src/Html2OpenXml/Expressions/Table/TableCaptionExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableCaptionExpression.cs @@ -55,7 +55,7 @@ public override IEnumerable Interpret (ParsingContext context) p.Append(childElements); var att = styleAttributes["text-align"]; - if (att.IsEmpty) att = node.GetAttribute("align"); + if (att.IsEmpty) att = node.GetAttribute("align").AsSpan(); if (!att.IsEmpty) { JustificationValues? align = Converter.ToParagraphAlign(att); diff --git a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs index 0cf036ec..05c471f9 100644 --- a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs @@ -87,15 +87,15 @@ protected override void ComposeStyles(ParsingContext context) var direction = styleAttributes["writing-mode"]; if (!direction.IsEmpty) { - if (direction.Equals("tb-lr", StringComparison.InvariantCultureIgnoreCase) || - direction.Equals("vertical-lr", StringComparison.InvariantCultureIgnoreCase)) + if (direction.Equals("tb-lr".AsSpan(), StringComparison.InvariantCultureIgnoreCase) || + direction.Equals("vertical-lr".AsSpan(), StringComparison.InvariantCultureIgnoreCase)) { cellProperties.TextDirection = new() { Val = TextDirectionValues.BottomToTopLeftToRight }; cellProperties.TableCellVerticalAlignment = new() { Val = TableVerticalAlignmentValues.Center }; paraProperties.Justification = new() { Val = JustificationValues.Center }; } - else if (direction.Equals("tb-rl", StringComparison.InvariantCultureIgnoreCase) || - direction.Equals("vertical-rl", StringComparison.InvariantCultureIgnoreCase)) + else if (direction.Equals("tb-rl".AsSpan(), StringComparison.InvariantCultureIgnoreCase) || + direction.Equals("vertical-rl".AsSpan(), StringComparison.InvariantCultureIgnoreCase)) { cellProperties.TextDirection = new() { Val = TextDirectionValues.TopToBottomRightToLeft }; cellProperties.TableCellVerticalAlignment = new() { Val = TableVerticalAlignmentValues.Center }; diff --git a/src/Html2OpenXml/Expressions/Table/TableElementExpressionBase.cs b/src/Html2OpenXml/Expressions/Table/TableElementExpressionBase.cs index a90e8382..f7614ced 100644 --- a/src/Html2OpenXml/Expressions/Table/TableElementExpressionBase.cs +++ b/src/Html2OpenXml/Expressions/Table/TableElementExpressionBase.cs @@ -72,7 +72,7 @@ protected override void ComposeStyles(ParsingContext context) base.ComposeStyles(context); var valign = Converter.ToVAlign(styleAttributes["vertical-align"]); - if (!valign.HasValue) valign = Converter.ToVAlign(node.GetAttribute("valign")); + if (!valign.HasValue) valign = Converter.ToVAlign(node.GetAttribute("valign").AsSpan()); if (!valign.HasValue) { // in Html, table cell are vertically centered by default @@ -92,7 +92,7 @@ protected override void ComposeStyles(ParsingContext context) } var halign = Converter.ToParagraphAlign(styleAttributes["text-align"]); - if (!halign.HasValue) halign = Converter.ToParagraphAlign(node.GetAttribute("align")); + if (!halign.HasValue) halign = Converter.ToParagraphAlign(node.GetAttribute("align").AsSpan()); if (halign.HasValue) { paraProperties.KeepNext = new(); diff --git a/src/Html2OpenXml/Expressions/Table/TableExpression.cs b/src/Html2OpenXml/Expressions/Table/TableExpression.cs index dd0e54db..abcf010b 100644 --- a/src/Html2OpenXml/Expressions/Table/TableExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableExpression.cs @@ -278,7 +278,7 @@ protected override void ComposeStyles (ParsingContext context) } } - var align = Converter.ToParagraphAlign(tableNode.GetAttribute("align")) + var align = Converter.ToParagraphAlign(tableNode.GetAttribute("align").AsSpan()) ?? Converter.ToParagraphAlign(styleAttributes["justify-self"]); if (!align.HasValue) {