Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSepideh Khoshnood <sekho@microsoft.com>2017-01-03 23:17:15 +0300
committerGitHub <noreply@github.com>2017-01-03 23:17:15 +0300
commitb119ec518b1ccc13e420862ff68dfbbd3bfee28e (patch)
tree606fd840c2a7e42552daaa3d8bfe3d420b7f1aac /src
parentde917aa252a5c5debed2769ee2f51dd07a1a4611 (diff)
parent318ede2acc1bb1ecb75d1c8b0bada2135081d9e6 (diff)
Merge pull request #14774 from sepidehMS/AddAsyncXLinqLoadSave
Add async XLinq document/element loading and saving
Diffstat (limited to 'src')
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XCData.cs24
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XComment.cs19
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs288
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocument.cs244
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocumentType.cs21
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XElement.cs259
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XLinq.cs80
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XNode.cs75
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XProcessingInstruction.cs19
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XText.cs23
-rw-r--r--src/System.Private.Xml.Linq/tests/XDocument.Common/BridgeHelpers.cs2
-rw-r--r--src/System.Private.Xml.Linq/tests/XDocument.Common/HelperExtensionMethods.cs2
-rw-r--r--src/System.Private.Xml.Linq/tests/XDocument.Common/XDocument.Common.csproj3
-rw-r--r--src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/XDocument.Test.ModuleCore.csproj3
-rw-r--r--src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/util.cs2
-rw-r--r--src/System.Private.Xml.Linq/tests/misc/LoadSaveAsyncTests.cs206
-rw-r--r--src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj5
-rw-r--r--src/System.Xml.XDocument/ref/System.Xml.XDocument.cs47
-rw-r--r--src/System.Xml.XDocument/ref/System.Xml.XDocument.csproj1
-rw-r--r--src/System.Xml.XDocument/src/ApiCompatBaseline.net463.txt23
20 files changed, 1227 insertions, 119 deletions
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XCData.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XCData.cs
index 551da96934..e9eee51faa 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XCData.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XCData.cs
@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Threading;
+using System.Threading.Tasks;
+
namespace System.Xml.Linq
{
/// <summary>
@@ -49,6 +52,27 @@ namespace System.Xml.Linq
writer.WriteCData(text);
}
+ /// <summary>
+ /// Write this <see cref="XCData"/> to the given <see cref="XmlWriter"/>.
+ /// </summary>
+ /// <param name="writer">
+ /// The <see cref="XmlWriter"/> to write this <see cref="XCData"/> to.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// The CancellationToken to use to request cancellation of this operation.
+ /// </param>
+ /// <returns>
+ /// A Task that represents the eventual completion of the operation.
+ /// </returns>
+ public override Task WriteToAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled(cancellationToken);
+ return writer.WriteCDataAsync(text);
+ }
+
internal override XNode CloneNode()
{
return new XCData(this);
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XComment.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XComment.cs
index 486d30e1bc..9018092dd4 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XComment.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XComment.cs
@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Threading;
+using System.Threading.Tasks;
+
namespace System.Xml.Linq
{
/// <summary>
@@ -93,6 +96,22 @@ namespace System.Xml.Linq
writer.WriteComment(value);
}
+ /// <summary>
+ /// Write this <see cref="XComment"/> to the passed in <see cref="XmlWriter"/>.
+ /// </summary>
+ /// <param name="writer">
+ /// The <see cref="XmlWriter"/> to write this <see cref="XComment"/> to.
+ /// </param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public override Task WriteToAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled(cancellationToken);
+ return writer.WriteCommentAsync(value);
+ }
+
internal override XNode CloneNode()
{
return new XComment(this);
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs
index 1315570edc..4c10ff7e3b 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
using Debug = System.Diagnostics.Debug;
using IEnumerable = System.Collections.IEnumerable;
@@ -853,53 +855,117 @@ namespace System.Xml.Linq
internal void ReadContentFrom(XmlReader r)
{
if (r.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
- XContainer c = this;
- NamespaceCache eCache = new NamespaceCache();
- NamespaceCache aCache = new NamespaceCache();
+
+ ContentReader cr = new ContentReader(this);
+ while (cr.ReadContentFrom(this, r) && r.Read()) ;
+ }
+
+ internal void ReadContentFrom(XmlReader r, LoadOptions o)
+ {
+ if ((o & (LoadOptions.SetBaseUri | LoadOptions.SetLineInfo)) == 0)
+ {
+ ReadContentFrom(r);
+ return;
+ }
+ if (r.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
+
+ ContentReader cr = new ContentReader(this);
+ while (cr.ReadContentFrom(this, r, o) && r.Read()) ;
+ }
+
+ internal async Task ReadContentFromAsync(XmlReader r, CancellationToken cancellationToken)
+ {
+ if (r.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
+
+ ContentReader cr = new ContentReader(this);
do
{
+ cancellationToken.ThrowIfCancellationRequested();
+ }
+ while (cr.ReadContentFrom(this, r) && await r.ReadAsync().ConfigureAwait(false));
+ }
+
+ internal async Task ReadContentFromAsync(XmlReader r, LoadOptions o, CancellationToken cancellationToken)
+ {
+ if ((o & (LoadOptions.SetBaseUri | LoadOptions.SetLineInfo)) == 0)
+ {
+ await ReadContentFromAsync(r, cancellationToken).ConfigureAwait(false);
+ return;
+ }
+ if (r.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
+
+ ContentReader cr = new ContentReader(this);
+ do
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ }
+ while (cr.ReadContentFrom(this, r, o) && await r.ReadAsync().ConfigureAwait(false));
+ }
+
+ private sealed class ContentReader
+ {
+ private readonly NamespaceCache _eCache = new NamespaceCache();
+ private readonly NamespaceCache _aCache = new NamespaceCache();
+ private readonly IXmlLineInfo _lineInfo;
+ private XContainer _currentContainer;
+ private string _baseUri;
+
+ public ContentReader(XContainer rootContainer)
+ {
+ _currentContainer = rootContainer;
+ }
+
+ public ContentReader(XContainer rootContainer, XmlReader r, LoadOptions o)
+ {
+ _currentContainer = rootContainer;
+ _baseUri = (o & LoadOptions.SetBaseUri) != 0 ? r.BaseURI : null;
+ _lineInfo = (o & LoadOptions.SetLineInfo) != 0 ? r as IXmlLineInfo : null;
+ }
+
+ public bool ReadContentFrom(XContainer rootContainer, XmlReader r)
+ {
switch (r.NodeType)
{
case XmlNodeType.Element:
- XElement e = new XElement(eCache.Get(r.NamespaceURI).GetName(r.LocalName));
+ XElement e = new XElement(_eCache.Get(r.NamespaceURI).GetName(r.LocalName));
if (r.MoveToFirstAttribute())
{
do
{
- e.AppendAttributeSkipNotify(new XAttribute(aCache.Get(r.Prefix.Length == 0 ? string.Empty : r.NamespaceURI).GetName(r.LocalName), r.Value));
+ e.AppendAttributeSkipNotify(new XAttribute(_aCache.Get(r.Prefix.Length == 0 ? string.Empty : r.NamespaceURI).GetName(r.LocalName), r.Value));
} while (r.MoveToNextAttribute());
r.MoveToElement();
}
- c.AddNodeSkipNotify(e);
+ _currentContainer.AddNodeSkipNotify(e);
if (!r.IsEmptyElement)
{
- c = e;
+ _currentContainer = e;
}
break;
case XmlNodeType.EndElement:
- if (c.content == null)
+ if (_currentContainer.content == null)
{
- c.content = string.Empty;
+ _currentContainer.content = string.Empty;
}
- if (c == this) return;
- c = c.parent;
+ if (_currentContainer == rootContainer) return false;
+ _currentContainer = _currentContainer.parent;
break;
case XmlNodeType.Text:
case XmlNodeType.SignificantWhitespace:
case XmlNodeType.Whitespace:
- c.AddStringSkipNotify(r.Value);
+ _currentContainer.AddStringSkipNotify(r.Value);
break;
case XmlNodeType.CDATA:
- c.AddNodeSkipNotify(new XCData(r.Value));
+ _currentContainer.AddNodeSkipNotify(new XCData(r.Value));
break;
case XmlNodeType.Comment:
- c.AddNodeSkipNotify(new XComment(r.Value));
+ _currentContainer.AddNodeSkipNotify(new XComment(r.Value));
break;
case XmlNodeType.ProcessingInstruction:
- c.AddNodeSkipNotify(new XProcessingInstruction(r.Name, r.Value));
+ _currentContainer.AddNodeSkipNotify(new XProcessingInstruction(r.Name, r.Value));
break;
case XmlNodeType.DocumentType:
- c.AddNodeSkipNotify(new XDocumentType(r.LocalName, r.GetAttribute("PUBLIC"), r.GetAttribute("SYSTEM"), r.Value));
+ _currentContainer.AddNodeSkipNotify(new XDocumentType(r.LocalName, r.GetAttribute("PUBLIC"), r.GetAttribute("SYSTEM"), r.Value));
break;
case XmlNodeType.EntityReference:
if (!r.CanResolveEntity) throw new InvalidOperationException(SR.InvalidOperation_UnresolvedEntityReference);
@@ -910,109 +976,97 @@ namespace System.Xml.Linq
default:
throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, r.NodeType));
}
- } while (r.Read());
- }
-
- internal void ReadContentFrom(XmlReader r, LoadOptions o)
- {
- if ((o & (LoadOptions.SetBaseUri | LoadOptions.SetLineInfo)) == 0)
- {
- ReadContentFrom(r);
- return;
+ return true;
}
- if (r.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
- XContainer c = this;
- XNode n = null;
- NamespaceCache eCache = new NamespaceCache();
- NamespaceCache aCache = new NamespaceCache();
- string baseUri = (o & LoadOptions.SetBaseUri) != 0 ? r.BaseURI : null;
- IXmlLineInfo li = (o & LoadOptions.SetLineInfo) != 0 ? r as IXmlLineInfo : null;
- do
+
+ public bool ReadContentFrom(XContainer rootContainer, XmlReader r, LoadOptions o)
{
- string uri = r.BaseURI;
+ XNode newNode = null;
+ string baseUri = r.BaseURI;
+
switch (r.NodeType)
{
case XmlNodeType.Element:
+ {
+ XElement e = new XElement(_eCache.Get(r.NamespaceURI).GetName(r.LocalName));
+ if (_baseUri != null && _baseUri != baseUri)
{
- XElement e = new XElement(eCache.Get(r.NamespaceURI).GetName(r.LocalName));
- if (baseUri != null && baseUri != uri)
- {
- e.SetBaseUri(uri);
- }
- if (li != null && li.HasLineInfo())
- {
- e.SetLineInfo(li.LineNumber, li.LinePosition);
- }
- if (r.MoveToFirstAttribute())
- {
- do
- {
- XAttribute a = new XAttribute(aCache.Get(r.Prefix.Length == 0 ? string.Empty : r.NamespaceURI).GetName(r.LocalName), r.Value);
- if (li != null && li.HasLineInfo())
- {
- a.SetLineInfo(li.LineNumber, li.LinePosition);
- }
- e.AppendAttributeSkipNotify(a);
- } while (r.MoveToNextAttribute());
- r.MoveToElement();
- }
- c.AddNodeSkipNotify(e);
- if (!r.IsEmptyElement)
+ e.SetBaseUri(baseUri);
+ }
+ if (_lineInfo != null && _lineInfo.HasLineInfo())
+ {
+ e.SetLineInfo(_lineInfo.LineNumber, _lineInfo.LinePosition);
+ }
+ if (r.MoveToFirstAttribute())
+ {
+ do
{
- c = e;
- if (baseUri != null)
+ XAttribute a = new XAttribute(_aCache.Get(r.Prefix.Length == 0 ? string.Empty : r.NamespaceURI).GetName(r.LocalName), r.Value);
+ if (_lineInfo != null && _lineInfo.HasLineInfo())
{
- baseUri = uri;
+ a.SetLineInfo(_lineInfo.LineNumber, _lineInfo.LinePosition);
}
- }
- break;
+ e.AppendAttributeSkipNotify(a);
+ } while (r.MoveToNextAttribute());
+ r.MoveToElement();
}
- case XmlNodeType.EndElement:
+ _currentContainer.AddNodeSkipNotify(e);
+ if (!r.IsEmptyElement)
{
- if (c.content == null)
- {
- c.content = string.Empty;
- }
- // Store the line info of the end element tag.
- // Note that since we've got EndElement the current container must be an XElement
- XElement e = c as XElement;
- Debug.Assert(e != null, "EndElement received but the current container is not an element.");
- if (e != null && li != null && li.HasLineInfo())
- {
- e.SetEndElementLineInfo(li.LineNumber, li.LinePosition);
- }
- if (c == this) return;
- if (baseUri != null && c.HasBaseUri)
+ _currentContainer = e;
+ if (_baseUri != null)
{
- baseUri = c.parent.BaseUri;
+ _baseUri = baseUri;
}
- c = c.parent;
- break;
}
+ break;
+ }
+ case XmlNodeType.EndElement:
+ {
+ if (_currentContainer.content == null)
+ {
+ _currentContainer.content = string.Empty;
+ }
+ // Store the line info of the end element tag.
+ // Note that since we've got EndElement the current container must be an XElement
+ XElement e = _currentContainer as XElement;
+ Debug.Assert(e != null, "EndElement received but the current container is not an element.");
+ if (e != null && _lineInfo != null && _lineInfo.HasLineInfo())
+ {
+ e.SetEndElementLineInfo(_lineInfo.LineNumber, _lineInfo.LinePosition);
+ }
+ if (_currentContainer == rootContainer) return false;
+ if (_baseUri != null && _currentContainer.HasBaseUri)
+ {
+ _baseUri = _currentContainer.parent.BaseUri;
+ }
+ _currentContainer = _currentContainer.parent;
+ break;
+ }
case XmlNodeType.Text:
case XmlNodeType.SignificantWhitespace:
case XmlNodeType.Whitespace:
- if ((baseUri != null && baseUri != uri) ||
- (li != null && li.HasLineInfo()))
+ if ((_baseUri != null && _baseUri != baseUri) ||
+ (_lineInfo != null && _lineInfo.HasLineInfo()))
{
- n = new XText(r.Value);
+ newNode = new XText(r.Value);
}
else
{
- c.AddStringSkipNotify(r.Value);
+ _currentContainer.AddStringSkipNotify(r.Value);
}
break;
case XmlNodeType.CDATA:
- n = new XCData(r.Value);
+ newNode = new XCData(r.Value);
break;
case XmlNodeType.Comment:
- n = new XComment(r.Value);
+ newNode = new XComment(r.Value);
break;
case XmlNodeType.ProcessingInstruction:
- n = new XProcessingInstruction(r.Name, r.Value);
+ newNode = new XProcessingInstruction(r.Name, r.Value);
break;
case XmlNodeType.DocumentType:
- n = new XDocumentType(r.LocalName, r.GetAttribute("PUBLIC"), r.GetAttribute("SYSTEM"), r.Value);
+ newNode = new XDocumentType(r.LocalName, r.GetAttribute("PUBLIC"), r.GetAttribute("SYSTEM"), r.Value);
break;
case XmlNodeType.EntityReference:
if (!r.CanResolveEntity) throw new InvalidOperationException(SR.InvalidOperation_UnresolvedEntityReference);
@@ -1023,20 +1077,25 @@ namespace System.Xml.Linq
default:
throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, r.NodeType));
}
- if (n != null)
+
+ if (newNode != null)
{
- if (baseUri != null && baseUri != uri)
+ if (_baseUri != null && _baseUri != baseUri)
{
- n.SetBaseUri(uri);
+ newNode.SetBaseUri(baseUri);
}
- if (li != null && li.HasLineInfo())
+
+ if (_lineInfo != null && _lineInfo.HasLineInfo())
{
- n.SetLineInfo(li.LineNumber, li.LinePosition);
+ newNode.SetLineInfo(_lineInfo.LineNumber, _lineInfo.LinePosition);
}
- c.AddNodeSkipNotify(n);
- n = null;
+
+ _currentContainer.AddNodeSkipNotify(newNode);
+ newNode = null;
}
- } while (r.Read());
+
+ return true;
+ }
}
internal void RemoveNode(XNode n)
@@ -1113,6 +1172,41 @@ namespace System.Xml.Linq
}
}
+ internal async Task WriteContentToAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ if (content != null)
+ {
+ string stringContent = content as string;
+
+ if (stringContent != null)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ Task tWrite;
+
+ if (this is XDocument)
+ {
+ tWrite = writer.WriteWhitespaceAsync(stringContent);
+ }
+ else
+ {
+ tWrite = writer.WriteStringAsync(stringContent);
+ }
+
+ await tWrite.ConfigureAwait(false);
+ }
+ else
+ {
+ XNode n = (XNode)content;
+ do
+ {
+ n = n.next;
+ await n.WriteToAsync(writer, cancellationToken).ConfigureAwait(false);
+ } while (n != content);
+ }
+ }
+ }
+
private static void AddContentToList(List<object> list, object content)
{
IEnumerable e = content is string ? null : content as IEnumerable;
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocument.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocument.cs
index a7f3ccd36f..1957ec2e14 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocument.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocument.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
using Encoding = System.Text.Encoding;
@@ -270,6 +272,42 @@ namespace System.Xml.Linq
/// <summary>
/// Create a new <see cref="XDocument"/> and initialize its underlying XML tree using
+ /// the passed <see cref="Stream"/> parameter. Optionally whitespace handling
+ /// can be preserved.
+ /// </summary>
+ /// <remarks>
+ /// If LoadOptions.PreserveWhitespace is enabled then
+ /// the underlying <see cref="XmlReaderSettings"/> property <see cref="XmlReaderSettings.IgnoreWhitespace"/>
+ /// is set to false.
+ /// </remarks>
+ /// <param name="stream">
+ /// A <see cref="Stream"/> containing the raw XML to read into the newly
+ /// created <see cref="XDocument"/>.
+ /// </param>
+ /// <param name="options">
+ /// A set of <see cref="LoadOptions"/>.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// A cancellation token.
+ /// </param>
+ /// <returns>
+ /// A new <see cref="XDocument"/> containing the contents of the passed in
+ /// <see cref="Stream"/>.
+ /// </returns>
+ public static async Task<XDocument> LoadAsync(Stream stream, LoadOptions options, CancellationToken cancellationToken)
+ {
+ XmlReaderSettings rs = GetXmlReaderSettings(options);
+
+ rs.Async = true;
+
+ using (XmlReader r = XmlReader.Create(stream, rs))
+ {
+ return await LoadAsync(r, options, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ /// <summary>
+ /// Create a new <see cref="XDocument"/> and initialize its underlying XML tree using
/// the passed <see cref="TextReader"/> parameter.
/// </summary>
/// <param name="textReader">
@@ -316,6 +354,42 @@ namespace System.Xml.Linq
}
/// <summary>
+ /// Create a new <see cref="XDocument"/> and initialize its underlying XML tree using
+ /// the passed <see cref="TextReader"/> parameter. Optionally whitespace handling
+ /// can be preserved.
+ /// </summary>
+ /// <remarks>
+ /// If LoadOptions.PreserveWhitespace is enabled then
+ /// the <see cref="XmlReaderSettings"/> property <see cref="XmlReaderSettings.IgnoreWhitespace"/>
+ /// is set to false.
+ /// </remarks>
+ /// <param name="textReader">
+ /// A <see cref="TextReader"/> containing the raw XML to read into the newly
+ /// created <see cref="XDocument"/>.
+ /// </param>
+ /// <param name="options">
+ /// A set of <see cref="LoadOptions"/>.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// A cancellation token.
+ /// </param>
+ /// <returns>
+ /// A new <see cref="XDocument"/> containing the contents of the passed in
+ /// <see cref="TextReader"/>.
+ /// </returns>
+ public static async Task<XDocument> LoadAsync(TextReader textReader, LoadOptions options, CancellationToken cancellationToken)
+ {
+ XmlReaderSettings rs = GetXmlReaderSettings(options);
+
+ rs.Async = true;
+
+ using (XmlReader r = XmlReader.Create(textReader, rs))
+ {
+ return await LoadAsync(r, options, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ /// <summary>
/// Create a new <see cref="XDocument"/> containing the contents of the
/// passed in <see cref="XmlReader"/>.
/// </summary>
@@ -351,6 +425,62 @@ namespace System.Xml.Linq
{
if (reader == null) throw new ArgumentNullException(nameof(reader));
if (reader.ReadState == ReadState.Initial) reader.Read();
+
+ XDocument d = InitLoad(reader, options);
+ d.ReadContentFrom(reader, options);
+
+ if( !reader.EOF) throw new InvalidOperationException(SR.InvalidOperation_ExpectedEndOfFile);
+ if (d.Root == null) throw new InvalidOperationException(SR.InvalidOperation_MissingRoot);
+ return d;
+ }
+
+ /// <summary>
+ /// Create a new <see cref="XDocument"/> containing the contents of the
+ /// passed in <see cref="XmlReader"/>.
+ /// </summary>
+ /// <param name="reader">
+ /// An <see cref="XmlReader"/> containing the XML to be read into the new
+ /// <see cref="XDocument"/>.
+ /// </param>
+ /// <param name="options">
+ /// A set of <see cref="LoadOptions"/>.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// A cancellation token.
+ /// </param>
+ /// <returns>
+ /// A new <see cref="XDocument"/> containing the contents of the passed
+ /// in <see cref="XmlReader"/>.
+ /// </returns>
+ public static Task<XDocument> LoadAsync(XmlReader reader, LoadOptions options, CancellationToken cancellationToken)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled<XDocument>(cancellationToken);
+ return LoadAsyncInternal(reader, options, cancellationToken);
+ }
+
+ private static async Task<XDocument> LoadAsyncInternal(XmlReader reader, LoadOptions options, CancellationToken cancellationToken)
+ {
+ if (reader.ReadState == ReadState.Initial)
+ {
+ await reader.ReadAsync().ConfigureAwait(false);
+ }
+
+ XDocument d = InitLoad(reader, options);
+ await d.ReadContentFromAsync(reader, options, cancellationToken).ConfigureAwait(false);
+
+ if (!reader.EOF) throw new InvalidOperationException(SR.InvalidOperation_ExpectedEndOfFile);
+ if (d.Root == null) throw new InvalidOperationException(SR.InvalidOperation_MissingRoot);
+ return d;
+ }
+
+ /// <summary>
+ /// Performs shared initialization between Load and LoadAsync.
+ /// </summary>
+ static XDocument InitLoad(XmlReader reader, LoadOptions options)
+ {
XDocument d = new XDocument();
if ((options & LoadOptions.SetBaseUri) != 0)
{
@@ -372,9 +502,6 @@ namespace System.Xml.Linq
{
d.Declaration = new XDeclaration(reader);
}
- d.ReadContentFrom(reader, options);
- if (!reader.EOF) throw new InvalidOperationException(SR.InvalidOperation_ExpectedEndOfFile);
- if (d.Root == null) throw new InvalidOperationException(SR.InvalidOperation_MissingRoot);
return d;
}
@@ -481,6 +608,40 @@ namespace System.Xml.Linq
}
/// <summary>
+ /// Output this <see cref="XDocument"/> to a <see cref="Stream"/>.
+ /// </summary>
+ /// <param name="stream">
+ /// The <see cref="Stream"/> to output the XML to.
+ /// </param>
+ /// <param name="options">
+ /// If SaveOptions.DisableFormatting is enabled the output is not indented.
+ /// If SaveOptions.OmitDuplicateNamespaces is enabled duplicate namespace declarations will be removed.
+ /// </param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public async Task SaveAsync(Stream stream, SaveOptions options, CancellationToken cancellationToken)
+ {
+ XmlWriterSettings ws = GetXmlWriterSettings(options);
+
+ ws.Async = true;
+
+ if (_declaration != null && !string.IsNullOrEmpty(_declaration.Encoding))
+ {
+ try
+ {
+ ws.Encoding = Encoding.GetEncoding(_declaration.Encoding);
+ }
+ catch (ArgumentException)
+ {
+ }
+ }
+
+ using (XmlWriter w = XmlWriter.Create(stream, ws))
+ {
+ await WriteToAsync(w, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ /// <summary>
/// Output this <see cref="XDocument"/> to the passed in <see cref="TextWriter"/>.
/// </summary>
/// <remarks>
@@ -529,6 +690,29 @@ namespace System.Xml.Linq
WriteTo(writer);
}
+ /// <summary>
+ /// Output this <see cref="XDocument"/> to a <see cref="TextWriter"/>.
+ /// </summary>
+ /// <param name="textWriter">
+ /// The <see cref="TextWriter"/> to output the XML to.
+ /// </param>
+ /// <param name="options">
+ /// If SaveOptions.DisableFormatting is enabled the output is not indented.
+ /// If SaveOptions.OmitDuplicateNamespaces is enabled duplicate namespace declarations will be removed.
+ /// </param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public async Task SaveAsync(TextWriter textWriter, SaveOptions options, CancellationToken cancellationToken)
+ {
+ XmlWriterSettings ws = GetXmlWriterSettings(options);
+
+ ws.Async = true;
+
+ using (XmlWriter w = XmlWriter.Create(textWriter, ws))
+ {
+ await WriteToAsync(w, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
///<overloads>
/// Outputs this <see cref="XDocument"/>'s underlying XML tree. The output can
/// be saved to a file, a <see cref="Stream"/>, a <see cref="TextWriter"/>,
@@ -554,6 +738,20 @@ namespace System.Xml.Linq
}
/// <summary>
+ /// Output this <see cref="XDocument"/> to an <see cref="XmlWriter"/>.
+ /// </summary>
+ /// <param name="writer">
+ /// The <see cref="XmlWriter"/> to output the XML to.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// A cancellation token.
+ /// </param>
+ public Task SaveAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ return WriteToAsync(writer, cancellationToken);
+ }
+
+ /// <summary>
/// Output this <see cref="XDocument"/> to a file.
/// </summary>
/// <param name="fileName">
@@ -611,6 +809,46 @@ namespace System.Xml.Linq
writer.WriteEndDocument();
}
+ /// <summary>
+ /// Output this <see cref="XDocument"/>'s underlying XML tree to the
+ /// passed in <see cref="XmlWriter"/>.
+ /// <seealso cref="XDocument.Save(XmlWriter)"/>
+ /// </summary>
+ /// <param name="writer">
+ /// The <see cref="XmlWriter"/> to output the content of this
+ /// <see cref="XDocument"/>.
+ /// </param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public override Task WriteToAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled(cancellationToken);
+ return WriteToAsyncInternal(writer, cancellationToken);
+ }
+
+ private async Task WriteToAsyncInternal(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ Task tStart;
+ if (_declaration != null && _declaration.Standalone == "yes")
+ {
+ tStart = writer.WriteStartDocumentAsync(true);
+ }
+ else if (_declaration != null && _declaration.Standalone == "no")
+ {
+ tStart = writer.WriteStartDocumentAsync(false);
+ }
+ else
+ {
+ tStart = writer.WriteStartDocumentAsync();
+ }
+ await tStart.ConfigureAwait(false);
+
+ await WriteContentToAsync(writer, cancellationToken).ConfigureAwait(false);
+ await writer.WriteEndDocumentAsync().ConfigureAwait(false);
+ }
+
internal override void AddAttribute(XAttribute a)
{
throw new ArgumentException(SR.Argument_AddAttribute);
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocumentType.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocumentType.cs
index 3f4a031d07..64c2ce977f 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocumentType.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XDocumentType.cs
@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Threading;
+using System.Threading.Tasks;
+
namespace System.Xml.Linq
{
/// <summary>
@@ -143,6 +146,24 @@ namespace System.Xml.Linq
writer.WriteDocType(_name, _publicId, _systemId, _internalSubset);
}
+ /// <summary>
+ /// Write this <see cref="XDocumentType"/> to the passed in <see cref="XmlWriter"/>.
+ /// </summary>
+ /// <param name="writer">
+ /// The <see cref="XmlWriter"/> to write this <see cref="XDocumentType"/> to.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// A cancellation token.
+ /// </param>
+ public override Task WriteToAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled(cancellationToken);
+ return writer.WriteDocTypeAsync(_name, _publicId, _systemId, _internalSubset);
+ }
+
internal override XNode CloneNode()
{
return new XDocumentType(this);
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XElement.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XElement.cs
index 61ef13bbeb..c15850ea25 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XElement.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XElement.cs
@@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using System.Xml.Schema;
+using System.Threading;
+using System.Threading.Tasks;
using CultureInfo = System.Globalization.CultureInfo;
using IEnumerable = System.Collections.IEnumerable;
@@ -137,11 +139,29 @@ namespace System.Xml.Linq
{
}
+ private XElement(AsyncConstructionSentry s)
+ {
+ // Dummy ctor used to avoid public default ctor. This is used
+ // by async methods meant to perform the same operations as
+ // the XElement constructors that do synchronous processing;
+ // the async methods instead construct an XElement using this
+ // constructor (which doesn't do any processing) and then themselves
+ // do the async processing. This is because ctors can't be 'async'.
+ }
+ private struct AsyncConstructionSentry { }
+
internal XElement(XmlReader r, LoadOptions o)
{
ReadElementFrom(r, o);
}
+ internal static async Task<XElement> CreateAsync(XmlReader r, CancellationToken cancellationToken)
+ {
+ XElement xe = new XElement(default(AsyncConstructionSentry));
+ await xe.ReadElementFromAsync(r, LoadOptions.None, cancellationToken).ConfigureAwait(false);
+ return xe;
+ }
+
///<overloads>
/// Outputs this <see cref="XElement"/>'s underlying XML tree. The output can
/// be saved to a file, a <see cref="Stream"/>, a <see cref="TextWriter"/>,
@@ -632,6 +652,42 @@ namespace System.Xml.Linq
return Load(r, options);
}
}
+
+ /// <summary>
+ /// Create a new <see cref="XElement"/> and initialize its underlying XML tree using
+ /// the passed <see cref="Stream"/> parameter. Optionally whitespace handling
+ /// can be preserved.
+ /// </summary>
+ /// <remarks>
+ /// If LoadOptions.PreserveWhitespace is enabled then
+ /// the <see cref="XmlReaderSettings"/> property <see cref="XmlReaderSettings.IgnoreWhitespace"/>
+ /// is set to false.
+ /// </remarks>
+ /// <param name="stream">
+ /// A <see cref="Stream"/> containing the raw XML to read into the newly
+ /// created <see cref="XElement"/>.
+ /// </param>
+ /// <param name="options">
+ /// A set of <see cref="LoadOptions"/>.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// A cancellation token.</param>
+ /// <returns>
+ /// A new <see cref="XElement"/> containing the contents of the passed in
+ /// <see cref="Stream"/>.
+ /// </returns>
+ public static async Task<XElement> LoadAsync(Stream stream, LoadOptions options, CancellationToken cancellationToken)
+ {
+ XmlReaderSettings rs = GetXmlReaderSettings(options);
+
+ rs.Async = true;
+
+ using (XmlReader r = XmlReader.Create(stream, rs))
+ {
+ return await LoadAsync(r, options, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
/// <summary>
/// Create a new <see cref="XElement"/> and initialize its underlying XML tree using
/// the passed <see cref="TextReader"/> parameter.
@@ -680,6 +736,41 @@ namespace System.Xml.Linq
}
/// <summary>
+ /// Create a new <see cref="XElement"/> and initialize its underlying XML tree using
+ /// the passed <see cref="TextReader"/> parameter. Optionally whitespace handling
+ /// can be preserved.
+ /// </summary>
+ /// <remarks>
+ /// If LoadOptions.PreserveWhitespace is enabled then
+ /// the <see cref="XmlReaderSettings"/> property <see cref="XmlReaderSettings.IgnoreWhitespace"/>
+ /// is set to false.
+ /// </remarks>
+ /// <param name="textReader">
+ /// A <see cref="TextReader"/> containing the raw XML to read into the newly
+ /// created <see cref="XElement"/>.
+ /// </param>
+ /// <param name="options">
+ /// A set of <see cref="LoadOptions"/>.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// A cancellation token.</param>
+ /// <returns>
+ /// A new <see cref="XElement"/> containing the contents of the passed in
+ /// <see cref="TextReader"/>.
+ /// </returns>
+ public static async Task<XElement> LoadAsync(TextReader textReader, LoadOptions options, CancellationToken cancellationToken)
+ {
+ XmlReaderSettings rs = GetXmlReaderSettings(options);
+
+ rs.Async = true;
+
+ using (XmlReader r = XmlReader.Create(textReader, rs))
+ {
+ return await LoadAsync(r, options, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ /// <summary>
/// Create a new <see cref="XElement"/> containing the contents of the
/// passed in <see cref="XmlReader"/>.
/// </summary>
@@ -721,6 +812,46 @@ namespace System.Xml.Linq
return e;
}
+ /// <summary>
+ /// Create a new <see cref="XElement"/> containing the contents of the
+ /// passed in <see cref="XmlReader"/>.
+ /// </summary>
+ /// <param name="reader">
+ /// An <see cref="XmlReader"/> containing the XML to be read into the new
+ /// <see cref="XElement"/>.
+ /// </param>
+ /// <param name="options">
+ /// A set of <see cref="LoadOptions"/>.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// A cancellation token.</param>
+ /// <returns>
+ /// A new <see cref="XElement"/> containing the contents of the passed
+ /// in <see cref="XmlReader"/>.
+ /// </returns>
+ public static Task<XElement> LoadAsync(XmlReader reader, LoadOptions options, CancellationToken cancellationToken)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled<XElement>(cancellationToken);
+ return LoadAsyncInternal(reader, options, cancellationToken);
+ }
+
+ private static async Task<XElement> LoadAsyncInternal(XmlReader reader, LoadOptions options, CancellationToken cancellationToken)
+ {
+ if (await reader.MoveToContentAsync().ConfigureAwait(false) != XmlNodeType.Element) throw new InvalidOperationException(SR.Format(SR.InvalidOperation_ExpectedNodeType, XmlNodeType.Element, reader.NodeType));
+
+ XElement e = new XElement(new AsyncConstructionSentry());
+ await e.ReadElementFromAsync(reader, options, cancellationToken).ConfigureAwait(false);
+
+ cancellationToken.ThrowIfCancellationRequested();
+ await reader.MoveToContentAsync().ConfigureAwait(false);
+
+ if (!reader.EOF) throw new InvalidOperationException(SR.InvalidOperation_ExpectedEndOfFile);
+ return e;
+ }
+
/// <overloads>
/// Parses a string containing XML into an <see cref="XElement"/>. Optionally
/// whitespace can be preserved.
@@ -933,6 +1064,29 @@ namespace System.Xml.Linq
}
/// <summary>
+ /// Output this <see cref="XElement"/> to a <see cref="Stream"/>.
+ /// </summary>
+ /// <param name="stream">
+ /// The <see cref="Stream"/> to output the XML to.
+ /// </param>
+ /// <param name="options">
+ /// If SaveOptions.DisableFormatting is enabled the output is not indented.
+ /// If SaveOptions.OmitDuplicateNamespaces is enabled duplicate namespace declarations will be removed.
+ /// </param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public async Task SaveAsync(Stream stream, SaveOptions options, CancellationToken cancellationToken)
+ {
+ XmlWriterSettings ws = GetXmlWriterSettings(options);
+
+ ws.Async = true;
+
+ using (XmlWriter w = XmlWriter.Create(stream, ws))
+ {
+ await SaveAsync(w, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ /// <summary>
/// Output this <see cref="XElement"/> to the passed in <see cref="TextWriter"/>.
/// </summary>
/// <remarks>
@@ -971,6 +1125,29 @@ namespace System.Xml.Linq
}
/// <summary>
+ /// Output this <see cref="XElement"/> to a <see cref="TextWriter"/>.
+ /// </summary>
+ /// <param name="textWriter">
+ /// The <see cref="TextWriter"/> to output the XML to.
+ /// </param>
+ /// <param name="options">
+ /// If SaveOptions.DisableFormatting is enabled the output is not indented.
+ /// If SaveOptions.OmitDuplicateNamespaces is enabled duplicate namespace declarations will be removed.
+ /// </param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public async Task SaveAsync(TextWriter textWriter, SaveOptions options, CancellationToken cancellationToken)
+ {
+ XmlWriterSettings ws = GetXmlWriterSettings(options);
+
+ ws.Async = true;
+
+ using (XmlWriter w = XmlWriter.Create(textWriter, ws))
+ {
+ await SaveAsync(w, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ /// <summary>
/// Output this <see cref="XElement"/> to an <see cref="XmlWriter"/>.
/// </summary>
/// <param name="writer">
@@ -985,6 +1162,32 @@ namespace System.Xml.Linq
}
/// <summary>
+ /// Output this <see cref="XElement"/> to an <see cref="XmlWriter"/>.
+ /// </summary>
+ /// <param name="writer">
+ /// The <see cref="XmlWriter"/> to output the XML to.
+ /// </param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public Task SaveAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled(cancellationToken);
+ return SaveAsyncInternal(writer, cancellationToken);
+ }
+
+ private async Task SaveAsyncInternal(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ await writer.WriteStartDocumentAsync().ConfigureAwait(false);
+
+ await WriteToAsync(writer, cancellationToken).ConfigureAwait(false);
+
+ cancellationToken.ThrowIfCancellationRequested();
+ await writer.WriteEndDocumentAsync().ConfigureAwait(false);
+ }
+
+ /// <summary>
/// Sets the value of an attribute. The value is assigned to the attribute with the given
/// name. If no attribute with the given name exists, a new attribute is added. If the
/// value is null, the attribute with the given name, if any, is deleted.
@@ -1095,6 +1298,22 @@ namespace System.Xml.Linq
}
/// <summary>
+ /// Write this <see cref="XElement"/> to the passed in <see cref="XmlTextWriter"/>.
+ /// </summary>
+ /// <param name="writer">
+ /// The <see cref="XmlTextWriter"/> to write this <see cref="XElement"/> to.
+ /// </param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public override Task WriteToAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled(cancellationToken);
+ return new ElementWriter(writer).WriteElementAsync(this, cancellationToken);
+ }
+
+ /// <summary>
/// Cast the value of this <see cref="XElement"/> to a <see cref="string"/>.
/// </summary>
/// <remarks>
@@ -1784,7 +2003,39 @@ namespace System.Xml.Linq
private void ReadElementFrom(XmlReader r, LoadOptions o)
{
- if (r.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
+ ReadElementFromImpl(r, o);
+
+ if (!r.IsEmptyElement)
+ {
+ r.Read();
+ ReadContentFrom(r, o);
+ }
+
+ r.Read();
+ }
+
+ private async Task ReadElementFromAsync(XmlReader r, LoadOptions o, CancellationToken cancellationTokentoken)
+ {
+ ReadElementFromImpl(r, o);
+
+ if (!r.IsEmptyElement)
+ {
+ cancellationTokentoken.ThrowIfCancellationRequested();
+ await r.ReadAsync().ConfigureAwait(false);
+
+ await ReadContentFromAsync(r, o, cancellationTokentoken).ConfigureAwait(false);
+ }
+
+ cancellationTokentoken.ThrowIfCancellationRequested();
+ await r.ReadAsync().ConfigureAwait(false);
+ }
+
+ /// <summary>
+ /// Shared implementation between ReadElementFrom / ReadElementFromAsync.
+ /// </summary>
+ private void ReadElementFromImpl(XmlReader r, LoadOptions o)
+ {
+ if(r.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
name = XNamespace.Get(r.NamespaceURI).GetName(r.LocalName);
if ((o & LoadOptions.SetBaseUri) != 0)
{
@@ -1816,12 +2067,6 @@ namespace System.Xml.Linq
} while (r.MoveToNextAttribute());
r.MoveToElement();
}
- if (!r.IsEmptyElement)
- {
- r.Read();
- ReadContentFrom(r, o);
- }
- r.Read();
}
internal void RemoveAttribute(XAttribute a)
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XLinq.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XLinq.cs
index 95d4cde8c4..5ae8f32a4a 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XLinq.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XLinq.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
using IEnumerable = System.Collections.IEnumerable;
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
@@ -246,6 +248,51 @@ namespace System.Xml.Linq
}
}
+ public async Task WriteElementAsync(XElement e, CancellationToken cancellationToken)
+ {
+ PushAncestors(e);
+ XElement root = e;
+ XNode n = e;
+ while (true)
+ {
+ e = n as XElement;
+ if (e != null)
+ {
+ await WriteStartElementAsync(e, cancellationToken).ConfigureAwait(false);
+ if (e.content == null)
+ {
+ await WriteEndElementAsync(cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ string s = e.content as string;
+ if (s != null)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ await _writer.WriteStringAsync(s).ConfigureAwait(false);
+ await WriteFullEndElementAsync(cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ n = ((XNode) e.content).next;
+ continue;
+ }
+ }
+ }
+ else
+ {
+ await n.WriteToAsync(_writer, cancellationToken).ConfigureAwait(false);
+ }
+ while (n != root && n == n.parent.content)
+ {
+ n = n.parent;
+ await WriteFullEndElementAsync(cancellationToken).ConfigureAwait(false);
+ }
+ if (n == root) break;
+ n = n.next;
+ }
+ }
+
private string GetPrefixOfNamespace(XNamespace ns, bool allowDefaultNamespace)
{
string namespaceName = ns.NamespaceName;
@@ -300,6 +347,13 @@ namespace System.Xml.Linq
_writer.WriteEndElement();
_resolver.PopScope();
}
+
+ private async Task WriteEndElementAsync(CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ await _writer.WriteEndElementAsync().ConfigureAwait(false);
+ _resolver.PopScope();
+ }
private void WriteFullEndElement()
{
@@ -307,6 +361,13 @@ namespace System.Xml.Linq
_resolver.PopScope();
}
+ private async Task WriteFullEndElementAsync(CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ await _writer.WriteFullEndElementAsync().ConfigureAwait(false);
+ _resolver.PopScope();
+ }
+
private void WriteStartElement(XElement e)
{
PushElement(e);
@@ -325,6 +386,25 @@ namespace System.Xml.Linq
} while (a != e.lastAttr);
}
}
+
+ async Task WriteStartElementAsync(XElement e, CancellationToken cancellationToken)
+ {
+ PushElement(e);
+ XNamespace ns = e.Name.Namespace;
+ await _writer.WriteStartElementAsync(GetPrefixOfNamespace(ns, true), e.Name.LocalName, ns.NamespaceName).ConfigureAwait(false);
+ XAttribute a = e.lastAttr;
+ if (a != null)
+ {
+ do
+ {
+ a = a.next;
+ ns = a.Name.Namespace;
+ string localName = a.Name.LocalName;
+ string namespaceName = ns.NamespaceName;
+ await _writer.WriteAttributeStringAsync(GetPrefixOfNamespace(ns, false), localName, namespaceName.Length == 0 && localName == "xmlns" ? XNamespace.xmlnsPrefixNamespace : namespaceName, a.Value).ConfigureAwait(false);
+ } while (a != e.lastAttr);
+ }
+ }
}
internal struct NamespaceResolver
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XNode.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XNode.cs
index b4740d5cad..110823dc16 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XNode.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XNode.cs
@@ -4,6 +4,8 @@
using System.Collections.Generic;
using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
using CultureInfo = System.Globalization.CultureInfo;
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
@@ -462,6 +464,72 @@ namespace System.Xml.Linq
}
/// <summary>
+ /// Creates an <see cref="XNode"/> from an <see cref="XmlReader"/>.
+ /// The runtime type of the node is determined by the node type
+ /// (<see cref="XObject.NodeType"/>) of the first node encountered
+ /// in the reader.
+ /// </summary>
+ /// <param name="reader">An <see cref="XmlReader"/> positioned at the node to read into this <see cref="XNode"/>.</param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ /// <returns>An <see cref="XNode"/> that contains the nodes read from the reader.</returns>
+ /// <exception cref="InvalidOperationException">
+ /// Thrown if the <see cref="XmlReader"/> is not positioned on a recognized node type.
+ /// </exception>
+ public static Task<XNode> ReadFromAsync(XmlReader reader, CancellationToken cancellationToken)
+ {
+ if (reader == null)
+ throw new ArgumentNullException(nameof(reader));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled<XNode>(cancellationToken);
+ return ReadFromAsyncInternal(reader, cancellationToken);
+ }
+
+ private static async Task<XNode> ReadFromAsyncInternal(XmlReader reader, CancellationToken cancellationToken)
+ {
+ if (reader.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
+
+ XNode ret;
+
+ switch (reader.NodeType)
+ {
+ case XmlNodeType.Text:
+ case XmlNodeType.SignificantWhitespace:
+ case XmlNodeType.Whitespace:
+ ret = new XText(reader.Value);
+ break;
+ case XmlNodeType.CDATA:
+ ret = new XCData(reader.Value);
+ break;
+ case XmlNodeType.Comment:
+ ret = new XComment(reader.Value);
+ break;
+ case XmlNodeType.DocumentType:
+ var name = reader.Name;
+ var publicId = reader.GetAttribute("PUBLIC");
+ var systemId = reader.GetAttribute("SYSTEM");
+ var internalSubset = reader.Value;
+
+ ret = new XDocumentType(name, publicId, systemId, internalSubset);
+ break;
+ case XmlNodeType.Element:
+ return await XElement.CreateAsync(reader, cancellationToken).ConfigureAwait(false);
+ case XmlNodeType.ProcessingInstruction:
+ var target = reader.Name;
+ var data = reader.Value;
+
+ ret = new XProcessingInstruction(target, data);
+ break;
+ default:
+ throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, reader.NodeType));
+ }
+
+ cancellationToken.ThrowIfCancellationRequested();
+ await reader.ReadAsync().ConfigureAwait(false);
+
+ return ret;
+ }
+
+ /// <summary>
/// Removes this XNode from the underlying XML tree.
/// </summary>
/// <exception cref="InvalidOperationException">
@@ -559,6 +627,13 @@ namespace System.Xml.Linq
/// <param name="writer">The <see cref="XmlWriter"/> to write the current node into.</param>
public abstract void WriteTo(XmlWriter writer);
+ /// <summary>
+ /// Write the current node to an <see cref="XmlWriter"/>.
+ /// </summary>
+ /// <param name="writer">The <see cref="XmlWriter"/> to write the current node into.</param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public abstract Task WriteToAsync(XmlWriter writer, CancellationToken cancellationToken);
+
internal virtual void AppendText(StringBuilder sb)
{
}
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XProcessingInstruction.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XProcessingInstruction.cs
index 2cb0214a01..2ad625fc61 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XProcessingInstruction.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XProcessingInstruction.cs
@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Threading;
+using System.Threading.Tasks;
+
namespace System.Xml.Linq
{
/// <summary>
@@ -119,6 +122,22 @@ namespace System.Xml.Linq
writer.WriteProcessingInstruction(target, data);
}
+ /// <summary>
+ /// Writes this <see cref="XProcessingInstruction"/> to the passed in <see cref="XmlWriter"/>.
+ /// </summary>
+ /// <param name="writer">
+ /// The <see cref="XmlWriter"/> to write this <see cref="XProcessingInstruction"/> to.
+ /// </param>
+ /// <param name="cancellationToken">A cancellation token.</param>
+ public override Task WriteToAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled(cancellationToken);
+ return writer.WriteProcessingInstructionAsync(target, data);
+ }
+
internal override XNode CloneNode()
{
return new XProcessingInstruction(this);
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XText.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XText.cs
index c31a668d34..7ca06139f0 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XText.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XText.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using StringBuilder = System.Text.StringBuilder;
+using System.Threading;
+using System.Threading.Tasks;
namespace System.Xml.Linq
{
@@ -90,6 +92,27 @@ namespace System.Xml.Linq
}
}
+ /// <summary>
+ /// Write this <see cref="XText"/> to the given <see cref="XmlWriter"/>.
+ /// </summary>
+ /// <param name="writer">
+ /// The <see cref="XmlWriter"/> to write this <see cref="XText"/> to.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// A cancellation token.
+ /// </param>
+ public override Task WriteToAsync(XmlWriter writer, CancellationToken cancellationToken)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+ if (cancellationToken.IsCancellationRequested)
+ return Task.FromCanceled(cancellationToken);
+
+ return parent is XDocument?
+ writer.WriteWhitespaceAsync(text) :
+ writer.WriteStringAsync(text);
+ }
+
internal override void AppendText(StringBuilder sb)
{
sb.Append(text);
diff --git a/src/System.Private.Xml.Linq/tests/XDocument.Common/BridgeHelpers.cs b/src/System.Private.Xml.Linq/tests/XDocument.Common/BridgeHelpers.cs
index f01688ee2d..5185156c8e 100644
--- a/src/System.Private.Xml.Linq/tests/XDocument.Common/BridgeHelpers.cs
+++ b/src/System.Private.Xml.Linq/tests/XDocument.Common/BridgeHelpers.cs
@@ -163,7 +163,7 @@ namespace CoreXml.Test.XLinq
}
}
- public string GetTestFileName()
+ public static string GetTestFileName()
{
return Path.Combine("TestData", "XmlReader", "API", pGenericXml);
}
diff --git a/src/System.Private.Xml.Linq/tests/XDocument.Common/HelperExtensionMethods.cs b/src/System.Private.Xml.Linq/tests/XDocument.Common/HelperExtensionMethods.cs
index c74b7eef66..f055d72ef9 100644
--- a/src/System.Private.Xml.Linq/tests/XDocument.Common/HelperExtensionMethods.cs
+++ b/src/System.Private.Xml.Linq/tests/XDocument.Common/HelperExtensionMethods.cs
@@ -12,8 +12,6 @@ using System.Xml.Linq;
using Microsoft.Test.ModuleCore;
-[assembly: System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
-
namespace CoreXml.Test.XLinq
{
public static class Helpers
diff --git a/src/System.Private.Xml.Linq/tests/XDocument.Common/XDocument.Common.csproj b/src/System.Private.Xml.Linq/tests/XDocument.Common/XDocument.Common.csproj
index 7275382504..0eeeb30e44 100644
--- a/src/System.Private.Xml.Linq/tests/XDocument.Common/XDocument.Common.csproj
+++ b/src/System.Private.Xml.Linq/tests/XDocument.Common/XDocument.Common.csproj
@@ -24,9 +24,6 @@
<Compile Include="InputSpace.cs" />
<Compile Include="ManagedNodeWriter.cs" />
<Compile Include="XLinqTestCase.cs" />
- <Compile Include="$(CommonPath)\System\Diagnostics\CodeAnalysis\ExcludeFromCodeCoverageAttribute.cs">
- <Link>Common\System\Diagnostics\CodeAnalysis\ExcludeFromCodeCoverageAttribute.cs</Link>
- </Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(CommonTestPath)\System\Xml\XmlCoreTest\XmlCoreTest.csproj" />
diff --git a/src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/XDocument.Test.ModuleCore.csproj b/src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/XDocument.Test.ModuleCore.csproj
index 84f5852feb..b45e771099 100644
--- a/src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/XDocument.Test.ModuleCore.csproj
+++ b/src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/XDocument.Test.ModuleCore.csproj
@@ -28,9 +28,6 @@
<Compile Include="testspec.cs" />
<Compile Include="testvariation.cs" />
<Compile Include="util.cs" />
- <Compile Include="$(CommonPath)\System\Diagnostics\CodeAnalysis\ExcludeFromCodeCoverageAttribute.cs">
- <Link>Common\System\Diagnostics\CodeAnalysis\ExcludeFromCodeCoverageAttribute.cs</Link>
- </Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\pkg\System.Private.Xml.Linq.pkgproj" />
diff --git a/src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/util.cs b/src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/util.cs
index ffb07d3b24..05b1611831 100644
--- a/src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/util.cs
+++ b/src/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/util.cs
@@ -5,8 +5,6 @@
using System;
using System.Collections.Generic;
-[assembly: System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
-
namespace Microsoft.Test.ModuleCore
{
////////////////////////////////////////////////////////////////
diff --git a/src/System.Private.Xml.Linq/tests/misc/LoadSaveAsyncTests.cs b/src/System.Private.Xml.Linq/tests/misc/LoadSaveAsyncTests.cs
new file mode 100644
index 0000000000..0c09af3d86
--- /dev/null
+++ b/src/System.Private.Xml.Linq/tests/misc/LoadSaveAsyncTests.cs
@@ -0,0 +1,206 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Linq;
+using XmlCoreTest.Common;
+using Xunit;
+
+namespace CoreXml.Test.XLinq
+{
+ public class LoadSaveAsyncTests : BridgeHelpers
+ {
+ [Fact]
+ public static void ArgumentValidation()
+ {
+ // Verify that ArgumentNullExceptions are thrown when passing null to LoadAsync and SaveAsync
+ Assert.Throws<ArgumentNullException>(() => { XDocument.LoadAsync((XmlReader)null, LoadOptions.None, CancellationToken.None); });
+ Assert.Throws<ArgumentNullException>(() => { new XDocument().SaveAsync((XmlWriter)null, CancellationToken.None); });
+ Assert.Throws<ArgumentNullException>(() => { XElement.LoadAsync((XmlReader)null, LoadOptions.None, CancellationToken.None); });
+ Assert.Throws<ArgumentNullException>(() => { new XElement("Name").SaveAsync((XmlWriter)null, CancellationToken.None); });
+ }
+
+ [Fact]
+ public static async Task AlreadyCanceled()
+ {
+ // Verify that providing an already canceled cancellation token will result in a canceled task
+
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => XDocument.LoadAsync(Stream.Null, LoadOptions.None, new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => XDocument.LoadAsync(StreamReader.Null, LoadOptions.None, new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => XDocument.LoadAsync(XmlReader.Create(Stream.Null), LoadOptions.None, new CancellationToken(true)));
+
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => new XDocument().SaveAsync(Stream.Null, SaveOptions.None, new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => new XDocument().SaveAsync(StreamWriter.Null, SaveOptions.None, new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => new XDocument().SaveAsync(XmlWriter.Create(Stream.Null), new CancellationToken(true)));
+
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => XElement.LoadAsync(Stream.Null, LoadOptions.None, new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => XElement.LoadAsync(StreamReader.Null, LoadOptions.None, new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => XElement.LoadAsync(XmlReader.Create(Stream.Null), LoadOptions.None, new CancellationToken(true)));
+
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => new XElement("Name").SaveAsync(Stream.Null, SaveOptions.None, new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => new XElement("Name").SaveAsync(StreamWriter.Null, SaveOptions.None, new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => new XElement("Name").SaveAsync(XmlWriter.Create(Stream.Null), new CancellationToken(true)));
+ }
+
+ [Theory]
+ [MemberData("RoundtripOptions_MemberData")]
+ public static async Task RoundtripSyncAsyncMatches_XmlReader(bool document, LoadOptions loadOptions, SaveOptions saveOptions)
+ {
+ // Create reader and writer settings
+ var readerSettings = new XmlReaderSettings();
+ var writerSettings = new XmlWriterSettings();
+ if ((saveOptions & SaveOptions.OmitDuplicateNamespaces) != 0)
+ {
+ writerSettings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
+ }
+ if ((saveOptions & SaveOptions.DisableFormatting) != 0)
+ {
+ writerSettings.Indent = false;
+ writerSettings.NewLineHandling = NewLineHandling.None;
+ }
+
+ // Roundtrip XML using synchronous and XmlReader/Writer
+ MemoryStream syncOutput = new MemoryStream();
+ using (XmlReader syncReader = XmlReader.Create(FilePathUtil.getStream(GetTestFileName()), readerSettings))
+ using (XmlWriter syncWriter = XmlWriter.Create(syncOutput, writerSettings))
+ {
+ if (document)
+ {
+ XDocument syncDoc = XDocument.Load(syncReader, loadOptions);
+ syncDoc.Save(syncWriter);
+ }
+ else
+ {
+ XElement syncElement = XElement.Load(syncReader, loadOptions);
+ syncElement.Save(syncWriter);
+ }
+ }
+
+ // Roundtrip XML using asynchronous and XmlReader/Writer
+ readerSettings.Async = true;
+ writerSettings.Async = true;
+ MemoryStream asyncOutput = new MemoryStream();
+ using (XmlReader asyncReader = XmlReader.Create(FilePathUtil.getStream(GetTestFileName()), readerSettings))
+ using (XmlWriter asyncWriter = XmlWriter.Create(asyncOutput, writerSettings))
+ {
+ if (document)
+ {
+ XDocument asyncDoc = await XDocument.LoadAsync(asyncReader, loadOptions, CancellationToken.None);
+ await asyncDoc.SaveAsync(asyncWriter, CancellationToken.None);
+ }
+ else
+ {
+ XElement asyncElement = await XElement.LoadAsync(asyncReader, loadOptions, CancellationToken.None);
+ await asyncElement.SaveAsync(asyncWriter, CancellationToken.None);
+ }
+ }
+
+ // Compare to make sure the synchronous and asynchronous results are the same
+ Assert.Equal(syncOutput.ToArray(), asyncOutput.ToArray());
+ }
+
+ [Theory]
+ [MemberData("RoundtripOptions_MemberData")]
+ public static async Task RoundtripSyncAsyncMatches_StreamReader(bool document, LoadOptions loadOptions, SaveOptions saveOptions)
+ {
+ // Roundtrip XML using synchronous and StreamReader/Writer
+ MemoryStream syncOutput = new MemoryStream();
+ using (StreamReader syncReader = new StreamReader(FilePathUtil.getStream(GetTestFileName())))
+ using (StreamWriter syncWriter = new StreamWriter(syncOutput))
+ {
+ if (document)
+ {
+ XDocument syncDoc = XDocument.Load(syncReader, loadOptions);
+ syncDoc.Save(syncWriter, saveOptions);
+ }
+ else
+ {
+ XElement syncElement = XElement.Load(syncReader, loadOptions);
+ syncElement.Save(syncWriter, saveOptions);
+ }
+ }
+
+ // Roundtrip XML using asynchronous and StreamReader/Writer
+ MemoryStream asyncOutput = new MemoryStream();
+ using (StreamReader asyncReader = new StreamReader(FilePathUtil.getStream(GetTestFileName())))
+ using (StreamWriter asyncWriter = new StreamWriter(asyncOutput))
+ {
+ if (document)
+ {
+ XDocument asyncDoc = await XDocument.LoadAsync(asyncReader, loadOptions, CancellationToken.None);
+ await asyncDoc.SaveAsync(asyncWriter, saveOptions, CancellationToken.None);
+ }
+ else
+ {
+ XElement asyncElement = await XElement.LoadAsync(asyncReader, loadOptions, CancellationToken.None);
+ await asyncElement.SaveAsync(asyncWriter, saveOptions, CancellationToken.None);
+ }
+ }
+
+ // Compare to make sure the synchronous and asynchronous results are the same
+ Assert.Equal(syncOutput.ToArray(), asyncOutput.ToArray());
+ }
+
+ [Theory]
+ [MemberData("RoundtripOptions_MemberData")]
+ public static async Task RoundtripSyncAsyncMatches_Stream(bool document, LoadOptions loadOptions, SaveOptions saveOptions)
+ {
+ // Roundtrip XML using synchronous and Stream
+ MemoryStream syncOutput = new MemoryStream();
+ using (Stream syncStream = FilePathUtil.getStream(GetTestFileName()))
+ {
+ if (document)
+ {
+ XDocument syncDoc = XDocument.Load(syncStream, loadOptions);
+ syncDoc.Save(syncOutput, saveOptions);
+ }
+ else
+ {
+ XElement syncElement = XElement.Load(syncStream, loadOptions);
+ syncElement.Save(syncOutput, saveOptions);
+ }
+ }
+
+ // Roundtrip XML using asynchronous and Stream
+ MemoryStream asyncOutput = new MemoryStream();
+ using (Stream asyncStream = FilePathUtil.getStream(GetTestFileName()))
+ {
+ if (document)
+ {
+ XDocument asyncDoc = await XDocument.LoadAsync(asyncStream, loadOptions, CancellationToken.None);
+ await asyncDoc.SaveAsync(asyncOutput, saveOptions, CancellationToken.None);
+ }
+ else
+ {
+ XElement asyncElement = await XElement.LoadAsync(asyncStream, loadOptions, CancellationToken.None);
+ await asyncElement.SaveAsync(asyncOutput, saveOptions, CancellationToken.None);
+ }
+ }
+
+ // Compare to make sure the synchronous and asynchronous results are the same
+ Assert.Equal(syncOutput.ToArray(), asyncOutput.ToArray());
+ }
+
+ // Inputs to the Roundtrip* tests:
+ // - Boolean for whether to test XDocument (true) or XElement (false)
+ // - LoadOptions value
+ // - SaveOptions value
+ public static IEnumerable<object[]> RoundtripOptions_MemberData
+ {
+ get
+ {
+ foreach (bool doc in new[] { true, false })
+ foreach (LoadOptions loadOptions in Enum.GetValues(typeof(LoadOptions)))
+ foreach (SaveOptions saveOptions in Enum.GetValues(typeof(SaveOptions)))
+ yield return new object[] { doc, loadOptions, saveOptions };
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj b/src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj
index 4e06e73275..36a4365c19 100644
--- a/src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj
+++ b/src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj
@@ -7,7 +7,7 @@
<ProjectGuid>{35FA1FA9-A504-4B9E-93F0-E5D03C21BECA}</ProjectGuid>
<OutputType>Library</OutputType>
<AssemblyName>System.Xml.Linq.Misc.Tests</AssemblyName>
- <NuGetTargetMoniker>.NETStandard,Version=v1.3</NuGetTargetMoniker>
+ <NuGetTargetMoniker>.NETStandard,Version=v1.7</NuGetTargetMoniker>
<RootNamespace>System.Xml.Linq.Tests</RootNamespace>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
@@ -23,12 +23,15 @@
<Compile Include="XHashtable.cs" />
<Compile Include="XLinqErrata4.cs" />
<Compile Include="XNameAPI.cs" />
+ <Compile Include="LoadSaveAsyncTests.cs" Condition="'$(TargetGroup)'==''" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="$(CommonTestPath)\System\Xml\ModuleCore\ModuleCore.csproj" />
<ProjectReference Include="$(CommonTestPath)\System\Xml\XmlCoreTest\XmlCoreTest.csproj" />
<ProjectReference Include="$(CommonTestPath)\System\Xml\XmlDiff\XmlDiff.csproj" />
<ProjectReference Include="..\XDocument.Common\XDocument.Common.csproj" />
<ProjectReference Include="..\XDocument.Test.ModuleCore\XDocument.Test.ModuleCore.csproj" />
+ <ProjectReference Include="..\..\..\System.Xml.XDocument\pkg\System.Xml.XDocument.pkgproj" />
<ProjectReference Include="..\..\pkg\System.Private.Xml.Linq.pkgproj" />
</ItemGroup>
<ItemGroup>
diff --git a/src/System.Xml.XDocument/ref/System.Xml.XDocument.cs b/src/System.Xml.XDocument/ref/System.Xml.XDocument.cs
index 26f13b069e..67eacced90 100644
--- a/src/System.Xml.XDocument/ref/System.Xml.XDocument.cs
+++ b/src/System.Xml.XDocument/ref/System.Xml.XDocument.cs
@@ -121,6 +121,9 @@ namespace System.Xml.Linq
public XCData(System.Xml.Linq.XCData other) : base(default(string)) { }
public override System.Xml.XmlNodeType NodeType { get { throw null; } }
public override void WriteTo(System.Xml.XmlWriter writer) { }
+#if netcoreapp11
+ public override System.Threading.Tasks.Task WriteToAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
}
public partial class XComment : System.Xml.Linq.XNode
{
@@ -129,6 +132,9 @@ namespace System.Xml.Linq
public override System.Xml.XmlNodeType NodeType { get { throw null; } }
public string Value { get { throw null; } set { } }
public override void WriteTo(System.Xml.XmlWriter writer) { }
+#if netcoreapp11
+ public override System.Threading.Tasks.Task WriteToAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
}
public abstract partial class XContainer : System.Xml.Linq.XNode
{
@@ -178,6 +184,11 @@ namespace System.Xml.Linq
public static System.Xml.Linq.XDocument Load(string uri, System.Xml.Linq.LoadOptions options) { throw null; }
public static System.Xml.Linq.XDocument Load(System.Xml.XmlReader reader) { throw null; }
public static System.Xml.Linq.XDocument Load(System.Xml.XmlReader reader, System.Xml.Linq.LoadOptions options) { throw null; }
+#if netcoreapp11
+ public static System.Threading.Tasks.Task<System.Xml.Linq.XDocument> LoadAsync(System.IO.Stream stream, System.Xml.Linq.LoadOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public static System.Threading.Tasks.Task<System.Xml.Linq.XDocument> LoadAsync(System.IO.TextReader textReader, System.Xml.Linq.LoadOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public static System.Threading.Tasks.Task<System.Xml.Linq.XDocument> LoadAsync(System.Xml.XmlReader reader, System.Xml.Linq.LoadOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
public static System.Xml.Linq.XDocument Parse(string text) { throw null; }
public static System.Xml.Linq.XDocument Parse(string text, System.Xml.Linq.LoadOptions options) { throw null; }
public void Save(System.IO.Stream stream) { }
@@ -187,7 +198,15 @@ namespace System.Xml.Linq
public void Save(System.Xml.XmlWriter writer) { }
public void Save(System.String fileName) { }
public void Save(System.String fileName, System.Xml.Linq.SaveOptions options) { }
+#if netcoreapp11
+ public System.Threading.Tasks.Task SaveAsync(System.IO.Stream stream, System.Xml.Linq.SaveOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public System.Threading.Tasks.Task SaveAsync(System.IO.TextWriter textWriter, System.Xml.Linq.SaveOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public System.Threading.Tasks.Task SaveAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
public override void WriteTo(System.Xml.XmlWriter writer) { }
+#if netcoreapp11
+ public override System.Threading.Tasks.Task WriteToAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
}
public partial class XDocumentType : System.Xml.Linq.XNode
{
@@ -199,6 +218,9 @@ namespace System.Xml.Linq
public string PublicId { get { throw null; } set { } }
public string SystemId { get { throw null; } set { } }
public override void WriteTo(System.Xml.XmlWriter writer) { }
+#if netcoreapp11
+ public override System.Threading.Tasks.Task WriteToAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
}
public partial class XElement : System.Xml.Linq.XContainer, System.Xml.Serialization.IXmlSerializable
{
@@ -235,6 +257,11 @@ namespace System.Xml.Linq
public static System.Xml.Linq.XElement Load(string uri, System.Xml.Linq.LoadOptions options) { throw null; }
public static System.Xml.Linq.XElement Load(System.Xml.XmlReader reader) { throw null; }
public static System.Xml.Linq.XElement Load(System.Xml.XmlReader reader, System.Xml.Linq.LoadOptions options) { throw null; }
+#if netcoreapp11
+ public static System.Threading.Tasks.Task<System.Xml.Linq.XElement> LoadAsync(System.IO.Stream stream, System.Xml.Linq.LoadOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public static System.Threading.Tasks.Task<System.Xml.Linq.XElement> LoadAsync(System.IO.TextReader textReader, System.Xml.Linq.LoadOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public static System.Threading.Tasks.Task<System.Xml.Linq.XElement> LoadAsync(System.Xml.XmlReader reader, System.Xml.Linq.LoadOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
[System.CLSCompliantAttribute(false)]
public static explicit operator bool (System.Xml.Linq.XElement element) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -300,6 +327,11 @@ namespace System.Xml.Linq
public void Save(System.Xml.XmlWriter writer) { }
public void Save(System.String fileName) { }
public void Save(System.String fileName, System.Xml.Linq.SaveOptions options) { }
+#if netcoreapp11
+ public System.Threading.Tasks.Task SaveAsync(System.IO.Stream stream, System.Xml.Linq.SaveOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public System.Threading.Tasks.Task SaveAsync(System.IO.TextWriter textWriter, System.Xml.Linq.SaveOptions options, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public System.Threading.Tasks.Task SaveAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
public void SetAttributeValue(System.Xml.Linq.XName name, object value) { }
public void SetElementValue(System.Xml.Linq.XName name, object value) { }
public void SetValue(object value) { }
@@ -307,6 +339,9 @@ namespace System.Xml.Linq
void System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader reader) { }
void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) { }
public override void WriteTo(System.Xml.XmlWriter writer) { }
+#if netcoreapp11
+ public override System.Threading.Tasks.Task WriteToAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
}
public sealed partial class XName : System.IEquatable<System.Xml.Linq.XName>, System.Runtime.Serialization.ISerializable
{
@@ -370,12 +405,18 @@ namespace System.Xml.Linq
public System.Collections.Generic.IEnumerable<System.Xml.Linq.XNode> NodesAfterSelf() { throw null; }
public System.Collections.Generic.IEnumerable<System.Xml.Linq.XNode> NodesBeforeSelf() { throw null; }
public static System.Xml.Linq.XNode ReadFrom(System.Xml.XmlReader reader) { throw null; }
+#if netcoreapp11
+ public static System.Threading.Tasks.Task<System.Xml.Linq.XNode> ReadFromAsync(System.Xml.XmlReader reader, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
public void Remove() { }
public void ReplaceWith(object content) { }
public void ReplaceWith(params object[] content) { }
public override string ToString() { throw null; }
public string ToString(System.Xml.Linq.SaveOptions options) { throw null; }
public abstract void WriteTo(System.Xml.XmlWriter writer);
+#if netcoreapp11
+ public abstract System.Threading.Tasks.Task WriteToAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken);
+#endif
}
public sealed partial class XNodeDocumentOrderComparer : System.Collections.Generic.IComparer<System.Xml.Linq.XNode>, System.Collections.IComparer
{
@@ -435,6 +476,9 @@ namespace System.Xml.Linq
public override System.Xml.XmlNodeType NodeType { get { throw null; } }
public string Target { get { throw null; } set { } }
public override void WriteTo(System.Xml.XmlWriter writer) { }
+#if netcoreapp11
+ public override System.Threading.Tasks.Task WriteToAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
}
public partial class XStreamingElement
{
@@ -462,6 +506,9 @@ namespace System.Xml.Linq
public override System.Xml.XmlNodeType NodeType { get { throw null; } }
public string Value { get { throw null; } set { } }
public override void WriteTo(System.Xml.XmlWriter writer) { }
+#if netcoreapp11
+ public override System.Threading.Tasks.Task WriteToAsync(System.Xml.XmlWriter writer, System.Threading.CancellationToken cancellationToken) { throw null; }
+#endif
}
}
namespace System.Xml.Schema
diff --git a/src/System.Xml.XDocument/ref/System.Xml.XDocument.csproj b/src/System.Xml.XDocument/ref/System.Xml.XDocument.csproj
index 20dd5717d9..2a039d6439 100644
--- a/src/System.Xml.XDocument/ref/System.Xml.XDocument.csproj
+++ b/src/System.Xml.XDocument/ref/System.Xml.XDocument.csproj
@@ -4,6 +4,7 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<NuGetTargetMoniker>.NETStandard,Version=v1.7</NuGetTargetMoniker>
+ <DefineConstants Condition="'$(TargetGroup)'==''">$(DefineConstants);netcoreapp11</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="System.Xml.XDocument.cs" />
diff --git a/src/System.Xml.XDocument/src/ApiCompatBaseline.net463.txt b/src/System.Xml.XDocument/src/ApiCompatBaseline.net463.txt
new file mode 100644
index 0000000000..bf1bfce8ae
--- /dev/null
+++ b/src/System.Xml.XDocument/src/ApiCompatBaseline.net463.txt
@@ -0,0 +1,23 @@
+Compat issues with assembly System.Xml.XDocument:
+MembersMustExist : Member 'System.Xml.Linq.XCData.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XComment.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XDocument.LoadAsync(System.IO.Stream, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XDocument.LoadAsync(System.IO.TextReader, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XDocument.LoadAsync(System.Xml.XmlReader, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XDocument.SaveAsync(System.IO.Stream, System.Xml.Linq.SaveOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XDocument.SaveAsync(System.IO.TextWriter, System.Xml.Linq.SaveOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XDocument.SaveAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XDocument.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XDocumentType.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XElement.LoadAsync(System.IO.Stream, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XElement.LoadAsync(System.IO.TextReader, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XElement.LoadAsync(System.Xml.XmlReader, System.Xml.Linq.LoadOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XElement.SaveAsync(System.IO.Stream, System.Xml.Linq.SaveOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XElement.SaveAsync(System.IO.TextWriter, System.Xml.Linq.SaveOptions, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XElement.SaveAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XElement.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XNode.ReadFromAsync(System.Xml.XmlReader, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XNode.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XProcessingInstruction.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Linq.XText.WriteToAsync(System.Xml.XmlWriter, System.Threading.CancellationToken)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 21 \ No newline at end of file