diff options
author | Sepideh Khoshnood <sekho@microsoft.com> | 2017-01-03 23:17:15 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-03 23:17:15 +0300 |
commit | b119ec518b1ccc13e420862ff68dfbbd3bfee28e (patch) | |
tree | 606fd840c2a7e42552daaa3d8bfe3d420b7f1aac /src | |
parent | de917aa252a5c5debed2769ee2f51dd07a1a4611 (diff) | |
parent | 318ede2acc1bb1ecb75d1c8b0bada2135081d9e6 (diff) |
Merge pull request #14774 from sepidehMS/AddAsyncXLinqLoadSave
Add async XLinq document/element loading and saving
Diffstat (limited to 'src')
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 |