AxDa.XamlDocConverter.Html
1.0.0
Prefix Reserved
Used project reference instead of package reference for AxDa.XamlDocConverter.Abstractions. This has been corrected in 1.0.1.
See the version list below for details.
dotnet add package AxDa.XamlDocConverter.Html --version 1.0.0
NuGet\Install-Package AxDa.XamlDocConverter.Html -Version 1.0.0
<PackageReference Include="AxDa.XamlDocConverter.Html" Version="1.0.0" />
<PackageVersion Include="AxDa.XamlDocConverter.Html" Version="1.0.0" />
<PackageReference Include="AxDa.XamlDocConverter.Html" />
paket add AxDa.XamlDocConverter.Html --version 1.0.0
#r "nuget: AxDa.XamlDocConverter.Html, 1.0.0"
#:package AxDa.XamlDocConverter.Html@1.0.0
#addin nuget:?package=AxDa.XamlDocConverter.Html&version=1.0.0
#tool nuget:?package=AxDa.XamlDocConverter.Html&version=1.0.0
WPF Flow Document HTML Converter
WPF Flow Document HTML Converter provides high-performance, low-allocating conversion from WPF flow document content to HTML and vice-versa.
Easily convert WPF flow document text content specified by a Microsoft WPF TextRange object or a XAML stream to the HTML language format, and vice versa.
WPF Flow Document HTML Converter uses .NET capabilities. It provides powerful conversion options and empowers developers to use the HTML text format in WPF applications.
HtmlXamlDocConverter overview
WPF Flow Document HTML Converter provides extensive conversion capabilities for serializing Microsoft WPF flow document content content to HTML, and vice versa.
Conversion is versatile. WPF Flow Document HTML Converter not only accepts and generates HTML documents, but also HTML document fragments.
Following is a simple example, converting a HTML document fragment to WPF flow document content:
using System.IO;
using AxDa.XamlDocConverter.Html;
// prepare HTML input ...
string html =
@"<body>
<h1>This is a heading.</h1>
<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<tbody>
<tr>
<th>Value 1</th>
<th>Value 2</th>
</tr>
</tbody>
</table>
</body>";
using MemoryStream htmlStream = new MemoryStream();
using MemoryStream xamlStream = new MemoryStream();
StreamWriter htmlWriter = new StreamWriter(htmlStream);
htmlWriter.Write(html);
htmlWriter.Flush();
htmlStream.Position = 0L;
// convert HTML to XAML ...
new HtmlXamlDocConverter().HtmlToXaml(htmlStream, xamlStream);
// output XAML ...
StreamReader xamlReader = new StreamReader(xamlStream);
xamlStream.Position = 0L;
string xaml = xamlReader.ReadToEnd();
The above code assigns the following result to the xaml
string variable:
<?xml version="1.0" encoding="UTF-8"?>
<Section xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Paragraph FontSize="24">
<Run>This is a heading.</Run>
</Paragraph>
<Table>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>
<Run>Column 1</Run>
</Paragraph>
</TableCell>
<TableCell>
<Paragraph>
<Run>Column 2</Run>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>
<Run>Value 1</Run>
</Paragraph>
</TableCell>
<TableCell>
<Paragraph>
<Run>Value 2</Run>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</Section>
How to Use
Converting WPF Flow Document content to HTML content, or vice versa, is easy:
In a WPF application, convert WPF document content to HTML by retrieving the TextRange
object from a Flow Document control and pass it to the HtmlXamlDocConverter.XamlToHtml()
method, along with a destination Stream
to receive the converted HTML content.
Conversely, to populate a WPF Flow Document control with rendered HTML content, provide the HtmlXamlDocConverter.HtmlToXaml()
method with a source Stream
containing HTML source code and the TextRange
object from a Flow Document control to be populated.
Instead of a TextRange
object, you can alternatively use a XAML stream, for example, from TextRange.Save()
.
Mapping HTML to WPF Flow Documents
The WPF flow document feature is designed to optimize text viewing and readability. Rather than being set to one predefined layout, flow documents dynamically adjust and reflow their content based on run-time variables such as window size, device resolution, and optional user preferences.
However, WPF Flow Documents do not support some features common to HTML. For example, heading, horizontal rule or quote block classes are missing from the System.Windows.Documents
namespace.
To be able to convert these elements from HTML to WPF XAML, and vice versa, the HtmlXamlDocConverter
class assumes a set of conventions for identifying XAML flow document elements as heading, horizontal rule, quotation block or code.
Heading
A
Paragraph
element is identified as a heading element if the following conditions are met:- The font size matches one of the font sizes defined in the
HeadingSizes
array property inXamlDocConverterOptions
.
Example
Assuming that the font size array in
XamlDocConverterOptions.HeadingSizes
is equal to[24, 20, 18, 16, 15, 14, 13]
, then<Paragraph FontSize="24"> <Run>This is heading level 1</Run> </Paragraph> <Paragraph FontSize="20"> <Run>This is heading level 2</Run> </Paragraph> <Paragraph FontSize="18"> <Run>This is heading level 3</Run> </Paragraph> <Paragraph FontSize="16"> <Run>This is heading level 4</Run> </Paragraph>
is converted to
<h1>This is heading level 1</h1> <h2>This is heading level 2</h2> <h3>This is heading level 3</h3> <h4>This is heading level 4</h4>
On the other hand, to have a paragraph with a specific font size not being recognized as a heading, set the paragraph's font size to any value other than the values defined in
HtmlXamlDocConverterOptions.HeadingSizes
.Example
<Paragraph FontSize="24.001"> <Run>This is not a heading</Run> </Paragraph>
is converted to
<p style="font-size: 24.001pt;">This is not a heading</p>
- The font size matches one of the font sizes defined in the
Horizontal Rule
A
Section
element is identified as a horizontal rule element if the following conditions are met:- It contains no child element
- It contains no text
- It has a top border – and only a border at the top – defined with the
BorderBrush
andBorderThickness
properties set - The thickness of the top border corresponds to the
HorizontalLineThickness
property defined inHtmlXamlDocConverterOptions
. All other border thickness values must be0
.
Example
<Section BorderThickness="0, 3, 0 ,0" BorderBrush="Silver"></Section>
is converted to
<hr/>
Quote Block
A
Section
element is identified as a quote block element if the following conditions are met:- It has a left border – and only a border on the left side – defined with the
BorderBrush
andBorderThickness
properties set - The left border thickness corresponds to the
BlockQuoteLineThickness
property defined inHtmlXamlDocConverterOptions
. All other border thickness values must be0
.
Example
<Section BorderThickness="3, 0, 0 ,0" BorderBrush="Silver"> <Paragraph> <Run>“This is the truth”.</Run> </Paragraph> </Section>
is converted to
<blockquote>“This is the truth”.</blockquote>
- It has a left border – and only a border on the left side – defined with the
Code Block
A
Section
element is identified as a code block element if the following conditions are met:- It is assigned a font family name that matches the font family name defined in the
MonospaceFontName
property of theHtmlXamlDocConverterOptions
object. - Optionally, a computer language acronym has been assigned to the
Tag
attribute.
Example
<Section FontFamily="Courier New" xml:space="preserve" Tag="c#"> <Paragraph> <Run><![CDATA[int = 1; return i;]]></Run> </Paragraph> </Section>
is converted to
<pre class="language-c#">int = 1; return i;</pre>
The computer language acronym is mapped to the resulting HTML element's
language-*
class, and vice versa. This enables JavaScript code syntax highlighters to recognize and colorize the corresponding section appropriately.- It is assigned a font family name that matches the font family name defined in the
Inline Code
A
Run
orSpan
element is identified as an inline code element if the following conditions are met:- It is assigned a font family name that matches the font family name defined in the
MonospaceFontName
property of theHtmlXamlDocConverterOptions
object.
Example
<Paragraph> <Run>The value is </Run> <Run FontFamily="Courier New" xml:space="preserve">true</Run> <Run>.</Run> </Paragraph>
is converted to
<p>The value is <code>true</code>.</p>
- It is assigned a font family name that matches the font family name defined in the
Implementation Details
HTML to XAML Flow Document Element Mapping
As explained above, XAML and HTML are similar in syntax but not in semantics. For example, HTML recognizes headings, while XAML flow documents do not.
To ensure acceptable yet comprehensive conversion, the HtmlXamlDocConverter
class makes some style assumptions for element mapping.
The following table provides some technical details about these features:
<dl> <dt> Headings <h1> … <h7></dt> <dd><br/>
A HTML heading is mapped to a Paragraph
object with a FontSize
attribute that matches one of the values in the HtmlXamlDocConverterOptions.HeadingSizes
array, and vice versa.
For example,
HtmlXamlDocConverterOptions.HeadingSizes[0]
matches<h1>
- …
HtmlXamlDocConverterOptions.HeadingSizes[3]
matches<h4>
The font size value must match exactly when converting from XAML to HTML. If you want to use a Paragraph
font size for decoration purposes but not for designating a heading, add a small fraction to either the corresponding Paragraph
object's FontSize
attribute or change the corresponding HtmlXamlDocConverterOptions.HeadingSizes
value. Then they won't be equal anymore and the corresponding Paragraph
object won't be interpreted as a heading.</dd>
<dt>Block Quote <blockquote></dt> <dd><br/>
A HTML block quote is mapped to a Section
object with BorderBrush
attribute set to an arbitrary value and left border thickness equals the HtmlXamlDocConverterOptions.BlockQuoteLineThickness
property value while all other border thicknesses are equal to 0
.
Example:
<Section BorderBrush="Silver" BorderThickness="3,0,0,0">
Section
BorderBrush
property value is taken from HtmlXamlDocConverterOptions.BlockQuoteLineColor
when converting from HTML to XAML.
When converting from XAML to Html, the actual color value is ignored, yet the BorderBrush
attribute must be present for the section being recognized as a block quote.
The Section
BorderThickness
property value must match exactly when converting from XAML to HTML. If you want to use a border for decoration purposes but not for designating a block quote, add a small fraction to either any value of the corresponding Section
object's BorderThickness
attribute or change the HtmlXamlDocConverterOptions.BlockQuoteLineThickness
value. Then they won't be equal anymore and the corresponding Section
object won't be interpreted as a block quote.</dd>
<dt>Horizontal Rule <hr></dt> <dd><br/>
A HTML horizontal rule is mapped to a Section
object that does not contain content, the BorderBrush
attribute is set to an arbitrary value and top border thickness equals the HtmlXamlDocConverterOptions.HorizontalLineThickness
property value while all other border thicknesses are equal to 0
.
Example:
<Section BorderBrush="Silver" BorderThickness="0,3,0,0"/>
Section
BorderBrush
property value is taken from HtmlXamlDocConverterOptions.HorizontalLineColor
when converting from HTML to XAML.
When converting from XAML to HTML, the actual color value is ignored, yet the BorderBrush
attribute must be present for the section being recognized as a horizontal rule.
The Section
BorderThickness
property value must match exactly when converting from XAML to HTML. If you want to use a border for decoration purposes but not for designating a horizontal rule, add a small fraction to either any value of the corresponding Section
object's BorderThickness
attribute or change the HtmlXamlDocConverterOptions.HorizontalLineThickness
value. Then they won't be equal anymore and the corresponding Section
object won't be interpreted as a horizontal rule.</dd>
<dt>Code Block <pre></dt> <dd><br/>
A HTML code block is mapped to a Section
object with a FontFamily
attribute set to a font matching Options.MonospaceFontName
.
When converting from XAML to HTML, the font family name must match exactly the font name from the Options.MonospaceFontName
property. Otherwise, the Section
will become a <div>
element with the font name applied as a CSS style rule.</dd>
<dt>Inline Code <code></dt> <dd><br/>
HTML inline code is mapped to a Run
or Span
object with a FontFamily
attribute set to a font matching Options.MonospaceFontName
.
When converting from XAML to HTML, the font family name must match exactly the font name from the Options.MonospaceFontName
property. Otherwise, the Run
or Span
will become a <span>
element with the font name applied as a CSS style rule.</dd>
</dl>
Supported Elements
The following table lists all HTML elements that are supported:
HTML Element |
---|
body |
li |
p |
span |
br |
b |
i |
u |
a |
table |
thead |
tbody |
tfoot |
tr |
th |
td |
The following table lists all XAML elements that are supported:
XAML Element |
---|
Section |
Paragraph |
Span |
Run |
Bold |
Italic |
Underline |
Hyperlink |
Floater |
LineBreak |
ListItem |
Table |
TableRowGroup |
TableRow |
TableCell |
Supported Text Attributes and Mappings
The following table lists all CSS rules and WPF attributes that are allowed and mapped to each other:
<br/>
The following table lists all HTML attributes and WPF attributes that are allowed and mapped to each other:
HTML Attribute | XAML Attribute |
---|---|
id |
Name |
href |
NavigateUri |
class |
Tag (Only if HTML class name begins with "language-". The text following the<br/> dash is assigned to the XAML element's Tag attribute and vice versa.<br/> This feature provides for code syntax highlighting.) |
xml:lang |
xml:lang |
lang |
xml:lang |
xml:space |
xml:space |
Remarks On Styles
The WPF Flow Document HTML Converter efficiently maps WPF XAML elements and attributes to HTML elements, attributes, and CSS rules, and vice versa.
The WPF Flow Document HTML Converter is text-based. It does not use a web browser to evaluate computed HTML element properties. Therefore, the converter only recognizes CSS styles applied directly to HTML elements. CSS classes, selectors, and stylesheets are ignored. The same applies to XAML, meaning styles and resources are ignored. Furthermore, property/style inheritance is not recognized in either XAML or HTML.
The properties of text elements in WPF flow documents and HTML CSS rules do not align. For example, compare WPF's device-independent units with CSS lengths, or the multitude of HTML elements with the limited number of elements in WPF flow documents. Due to the inherent differences between these two languages, it is impossible to convert a WPF flow document to HTML and vice versa without causing some discrepancies in appearance.
Only a limited number of HTML attributes and CSS rules are recognized and accepted for being mapped to WPF properties and vice versa. Any other HTML attributes, CSS rules, or XAML attributes unknown to this converter will throw a NotImplementedException
. Set the HtmlTextRangeConverterOptions.IgnoreUnknownProperties
property to true
to optionally ignore unknown XAML element properties, HTML element attributes, and CSS rules.
The same applies to unsupported HTML elements and WPF classes. HTML elements and WPF classes unknown to the converter throw a NotImplementedException
. You can define custom mappings for HTML elements and WPF classes unknown to the converter by adding individual element mappings to the HtmlTextRangeConverterOptions.AdditionalElementMapping
collection. Your custom mappings are applied only to elements unknown to the converter. The built-in mapping cannot be overridden.
Options
WPF Flow Document HTML Converter provides a rich set of conversion options. You can configure conversion details using the following HtmlXamlDocConverterOptions
properties:
<dl> <dt>HeadingSizes</dt> <dd>
Collection of XAML font sizes used to recognize a Paragraph
element for being interpreted as the corresponding heading level in the target format.
The default values are: [24, 20, 18, 16, 15, 14, 13]
.</dd>
<dt>MonospaceFontName</dt> <dd>
Font name used to recognize Paragraph
, Run
or Span
elements as being interpreted as code elements in the target format.
The default font family name is "Courier New
".</dd>
<dt>BlockQuoteLineThickness</dt> <dd>
Left side border thickness used for recognizing a block quote.
The default value is 3
.</dd>
<dt>BlockQuoteLineColor</dt> <dd>
Left border Color
used for displaying a block quote.
The default value is Colors.Silver
.</dd>
<dt>HorizontalLineThickness</dt> <dd>
Top border thickness used for recognizing a horizontal rule.
The default value is 3
.</dd>
<dt>HorizontalLineColor</dt> <dd>
Top border Color
used for displaying a horizontal rule.
The default value is Colors.Silver
.</dd>
<dt>CssFontSizeUnit</dt> <dd>
CSS unit used for converting XAML font size attribute to HTML.
The default value is "pt
".</dd>
<dt>CssThicknessUnit</dt> <dd>
CSS unit used for converting XAML margin, padding, width and height attributes to HTML.
The default value is "px
".</dd>
<dt>CssBorderWidthUnit</dt> <dd>
CSS unit used for converting XAML border width attribute to HTML.
The default value is "px
".</dd>
<dt>AdditionalElementMapping</dt> <dd>
Allows to add user defined mappings from source document element to target document element names.
Use this property for specifying custom mappings between additional HTML and WPF flow document elements not covered by this implementation.
To declare a custom element mapping to be used by a conversion, specify the element name from your source document as the key for the Dictionary{string, ElementInfo}
and create a new ElementInfo
object declaring the target element name and flow type.</dd>
<dt>IgnoreUnknownProperties</dt> <dd>
If true
, unknown XAML properties and CSS styles in the source document are ignored.
The default value is false
. Unknown XAML properties and CSS styles will throw NotImplementedException.</dd>
<dt>Indent</dt> <dd>
If true
, output is prettified, i.e., new-lines and indentation will be added to each element. Set to false
to not add white-space between elements.
The default value is true
.</dd>
<dt>AsDocumentFragment</dt> <dd>
If true
, the converted HTML tree will be a HTML document fragment, containing the converted elements only. If false
, a full HTML document will be generated, with the child tree embedded within the HTML <body>
element.
The default value is false
.</dd>
<dt>LintXmlSpaceAttribute</dt> <dd>
Determines whether redundant xml:space
attributes will be removed from the generated HTML document.
When converting a XAML document to HTML, existing xml:space
attributes are transpiled into CSS white-space
rules. However, when serializing the created HTML document, xml:space
attributes are required for the serializer to correctly format the resulting HTML. This is particularly true for elements rendered with xml:space="preserve"
.
The xml:space
attribute is ignored by HTML processors, so it's plain redundant if left in the resulting HTML document. Removing it from the resulting HTML comes with a performance penalty and additional memory requirements. So, you may want to opt-out of this linting step in order to improve performance and reduce the memory footprint of the conversion process.
The default value is true
.</dd>
</dl>
Known Issues
The current implementation of the Microsoft TextRange
class (.NET ⇐ v10.0) does not allow for navigating through its child content (See WPF issue #10095). So, internally WPF Flow Document HTML Converter saves the TextRange
content to a XAML stream using TextRange.Save()
and the resulting XAML is taken as source for conversion. The TextRange.Save()
method, however, does not save BlockUIContainer
content. Thus, conversion is restricted to be text-only because image content cannot be gathered.
Feedback, Sponsorship and Contact
You may reach me on axeldahmen.de or LinkedIn
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0-windows7.0 is compatible. net10.0-windows was computed. |
-
net9.0-windows7.0
- AxDa.EnhancedXmlWriter (>= 1.0.0)
- AxDa.XamlDocConverter.Abstractions (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.