Skip to content

Commit 10fbca3

Browse files
committed
Merge branch 'main' into issue-1903
2 parents 24da52f + 6847874 commit 10fbca3

File tree

9 files changed

+656
-2
lines changed

9 files changed

+656
-2
lines changed

Directory.Build.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<LatestTargetFramework>net8.0</LatestTargetFramework>
7171
<SamplesFrameworks>net8.0</SamplesFrameworks>
7272
<SamplesFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(SamplesFrameworks);net472</SamplesFrameworks>
73+
<DefineConstants Condition=" '$(TargetFramework)' != 'net35' And '$(TargetFramework)' != 'net40' And '$(TargetFramework)' != 'net46' And '$(TargetFramework)' != 'net472' ">$(DefineConstants);FEATURE_ASYNC_SAX_XML</DefineConstants>
7374
</PropertyGroup>
7475
</Otherwise>
7576
</Choose>

src/DocumentFormat.OpenXml.Framework/OpenXmlPartWriter.cs

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
using System.Collections.Generic;
77
using System.IO;
88
using System.Text;
9+
#if FEATURE_ASYNC_SAX_XML
10+
using DocumentFormat.OpenXml.Framework;
11+
using System.Threading.Tasks;
12+
#endif
913
using System.Xml;
1014

1115
namespace DocumentFormat.OpenXml
@@ -56,6 +60,36 @@ public OpenXmlPartWriter(OpenXmlPart openXmlPart, Encoding encoding)
5660
_xmlWriter = XmlWriter.Create(partStream, settings);
5761
}
5862

63+
/// <summary>
64+
/// Initializes a new instance of the OpenXmlPartWriter.
65+
/// </summary>
66+
/// <param name="openXmlPart">The OpenXmlPart to be written to.</param>
67+
/// <param name="settings">The settings for the OpenXmlPartWriter.</param>
68+
public OpenXmlPartWriter(OpenXmlPart openXmlPart, OpenXmlPartWriterSettings settings)
69+
{
70+
if (openXmlPart is null)
71+
{
72+
throw new ArgumentNullException(nameof(openXmlPart));
73+
}
74+
75+
if (settings is null)
76+
{
77+
throw new ArgumentNullException(nameof(settings));
78+
}
79+
80+
var partStream = openXmlPart.GetStream(FileMode.Create);
81+
XmlWriterSettings xmlWriterSettings = new()
82+
{
83+
CloseOutput = true,
84+
Encoding = settings.Encoding,
85+
#if FEATURE_ASYNC_SAX_XML
86+
Async = settings.Async,
87+
#endif
88+
};
89+
90+
_xmlWriter = XmlWriter.Create(partStream, xmlWriterSettings);
91+
}
92+
5993
/// <summary>
6094
/// Initializes a new instance of the OpenXmlPartWriter.
6195
/// </summary>
@@ -91,6 +125,35 @@ public OpenXmlPartWriter(Stream partStream, Encoding encoding)
91125
_xmlWriter = XmlWriter.Create(partStream, settings);
92126
}
93127

128+
/// <summary>
129+
/// Initializes a new instance of the OpenXmlPartWriter.
130+
/// </summary>
131+
/// <param name="partStream">The given part stream.</param>
132+
/// <param name="settings">The settings for the OpenXmlPartWriter.</param>
133+
public OpenXmlPartWriter(Stream partStream, OpenXmlPartWriterSettings settings)
134+
{
135+
if (partStream is null)
136+
{
137+
throw new ArgumentNullException(nameof(partStream));
138+
}
139+
140+
if (settings is null)
141+
{
142+
throw new ArgumentNullException(nameof(settings));
143+
}
144+
145+
XmlWriterSettings xmlWriterSettings = new()
146+
{
147+
CloseOutput = settings.CloseOutput,
148+
Encoding = settings.Encoding,
149+
#if FEATURE_ASYNC_SAX_XML
150+
Async = settings.Async,
151+
#endif
152+
};
153+
154+
_xmlWriter = XmlWriter.Create(partStream, xmlWriterSettings);
155+
}
156+
94157
#region public OpenXmlWriter methods
95158

96159
/// <summary>
@@ -365,5 +428,184 @@ public override void Close()
365428
}
366429

367430
#endregion
431+
432+
// Async Methods
433+
#if FEATURE_ASYNC_SAX_XML
434+
/// <summary>
435+
/// Asynchronously writes the XML declaration with the version "1.0".
436+
/// </summary>
437+
public override Task WriteStartDocumentAsync()
438+
{
439+
ThrowIfObjectDisposed();
440+
441+
return _xmlWriter.WriteStartDocumentAsync();
442+
}
443+
444+
/// <summary>
445+
/// Asynchronously writes the XML declaration with the version "1.0" and the standalone attribute.
446+
/// </summary>
447+
/// <param name="standalone">If true, it writes "standalone=yes"; if false, it writes "standalone=no". </param>
448+
public override Task WriteStartDocumentAsync(bool standalone)
449+
{
450+
ThrowIfObjectDisposed();
451+
452+
return _xmlWriter.WriteStartDocumentAsync(standalone);
453+
}
454+
455+
/// <summary>
456+
/// Asynchronously writes out a start tag of the element and all the attributes of the element.
457+
/// </summary>
458+
/// <param name="elementObject">The OpenXmlElement object to be written.</param>
459+
public async override Task WriteStartElementAsync(OpenXmlElement elementObject)
460+
{
461+
if (elementObject is null)
462+
{
463+
throw new ArgumentNullException(nameof(elementObject));
464+
}
465+
466+
if (elementObject is OpenXmlMiscNode)
467+
{
468+
throw new ArgumentOutOfRangeException(nameof(elementObject));
469+
}
470+
471+
ThrowIfObjectDisposed();
472+
473+
await _xmlWriter.WriteStartElementAsync(elementObject.Prefix, elementObject.LocalName, elementObject.NamespaceUri).ConfigureAwait(true);
474+
475+
if (elementObject.HasAttributes)
476+
{
477+
// write attributes
478+
foreach (var attribute in elementObject.GetAttributes())
479+
{
480+
await _xmlWriter.WriteAttributeStringAsync(attribute.Prefix, attribute.LocalName, attribute.NamespaceUri, attribute.Value).ConfigureAwait(true);
481+
}
482+
}
483+
484+
if (elementObject is OpenXmlLeafTextElement)
485+
{
486+
_isLeafTextElementStart = true;
487+
}
488+
else
489+
{
490+
_isLeafTextElementStart = false;
491+
}
492+
}
493+
494+
/// <summary>
495+
/// Asynchronously writes out a start tag of the element. And write the attributes in attributes. The attributes of the element will be omitted.
496+
/// </summary>
497+
/// <param name="elementObject">The OpenXmlElement object to be written.</param>
498+
/// <param name="attributes">The attributes to be written.</param>
499+
public override Task WriteStartElementAsync(OpenXmlElement elementObject, IEnumerable<OpenXmlAttribute> attributes)
500+
{
501+
if (elementObject is null)
502+
{
503+
throw new ArgumentNullException(nameof(elementObject));
504+
}
505+
506+
return WriteStartElementAsync(elementObject, attributes, elementObject.NamespaceDeclarations);
507+
}
508+
509+
/// <summary>
510+
/// Asynchronously writes out a start tag of the element. And write the attributes in attributes. The attributes of the element will be omitted.
511+
/// </summary>
512+
/// <param name="elementObject">The OpenXmlElement object to be written.</param>
513+
/// <param name="attributes">The attributes to be written.</param>
514+
/// <param name="namespaceDeclarations">The namespace declarations to be written, can be null if no namespace declarations.</param>
515+
public async override Task WriteStartElementAsync(OpenXmlElement elementObject, IEnumerable<OpenXmlAttribute> attributes, IEnumerable<KeyValuePair<string, string>> namespaceDeclarations)
516+
{
517+
if (elementObject is null)
518+
{
519+
throw new ArgumentNullException(nameof(elementObject));
520+
}
521+
522+
if (elementObject is OpenXmlMiscNode)
523+
{
524+
throw new ArgumentOutOfRangeException(nameof(elementObject));
525+
}
526+
527+
ThrowIfObjectDisposed();
528+
529+
await _xmlWriter.WriteStartElementAsync(elementObject.Prefix, elementObject.LocalName, elementObject.NamespaceUri).ConfigureAwait(true);
530+
531+
if (namespaceDeclarations is not null)
532+
{
533+
foreach (var item in namespaceDeclarations)
534+
{
535+
await _xmlWriter.WriteAttributeStringAsync(OpenXmlElementContext.XmlnsPrefix, item.Key, OpenXmlElementContext.XmlnsUri, item.Value).ConfigureAwait(true);
536+
}
537+
}
538+
539+
if (attributes is not null)
540+
{
541+
// write attributes
542+
foreach (var attribute in attributes)
543+
{
544+
await _xmlWriter.WriteAttributeStringAsync(attribute.Prefix, attribute.LocalName, attribute.NamespaceUri, attribute.Value).ConfigureAwait(true);
545+
}
546+
}
547+
548+
if (elementObject is OpenXmlLeafTextElement)
549+
{
550+
_isLeafTextElementStart = true;
551+
}
552+
else
553+
{
554+
_isLeafTextElementStart = false;
555+
}
556+
}
557+
558+
/// <summary>
559+
/// Asynchronously closes one element.
560+
/// </summary>
561+
public override Task WriteEndElementAsync()
562+
{
563+
ThrowIfObjectDisposed();
564+
565+
_isLeafTextElementStart = false;
566+
567+
return _xmlWriter.WriteEndElementAsync();
568+
}
569+
570+
/// <summary>
571+
/// Asynchronously writes the OpenXmlElement to the writer.
572+
/// </summary>
573+
/// <param name="elementObject">The OpenXmlElement object to be written.</param>
574+
public async override Task WriteElementAsync(OpenXmlElement elementObject)
575+
{
576+
if (elementObject is null)
577+
{
578+
throw new ArgumentNullException(nameof(elementObject));
579+
}
580+
581+
ThrowIfObjectDisposed();
582+
583+
await WriteStartElementAsync(elementObject).ConfigureAwait(true);
584+
585+
await WriteEndElementAsync().ConfigureAwait(true);
586+
587+
_isLeafTextElementStart = false;
588+
}
589+
590+
/// <summary>
591+
/// Asynchronously writes the given text content.
592+
/// </summary>
593+
/// <param name="text">The text to be written. </param>
594+
public override Task WriteStringAsync(string text)
595+
{
596+
ThrowIfObjectDisposed();
597+
598+
if (_isLeafTextElementStart)
599+
{
600+
return _xmlWriter.WriteStringAsync(text);
601+
}
602+
else
603+
{
604+
throw new InvalidOperationException(ExceptionMessages.InvalidWriteStringCall);
605+
}
606+
607+
// can continue WriteStringAsync(), so don't set _isLeafTextElementStart to false.
608+
}
609+
#endif
368610
}
369611
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Text;
5+
6+
namespace DocumentFormat.OpenXml;
7+
8+
/// <summary>
9+
/// Settings for the OpenXmlPartWriter.
10+
/// </summary>
11+
public class OpenXmlPartWriterSettings
12+
{
13+
#if FEATURE_ASYNC_SAX_XML
14+
/// <summary>
15+
/// Gets or sets a value indicating whether asynchronous OpenXmlPartWriter methods can be used.
16+
/// </summary>
17+
public bool Async { get; set; }
18+
#endif
19+
20+
/// <summary>
21+
/// Gets or sets a value indicating whether the OpenXmlPartWriter should check to ensure that all characters in the document conform to the "2.2 Characters" section of the W3C XML 1.0 Recommendation.
22+
/// </summary>
23+
public bool CloseOutput { get; set; }
24+
25+
/// <summary>
26+
/// Gets or sets a value indicating whether the OpenXmlPartWriter should also close the underlying stream or TextWriter when the Close() method is called.
27+
/// </summary>
28+
public Encoding Encoding { get; set; } = Encoding.UTF8;
29+
}

0 commit comments

Comments
 (0)