-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Add async document/element loading for XLinq. #110
Changes from all commits
5a53c6f
ded599b
715267a
035582e
5989550
987761e
b4c3d55
c7ed7dd
e7b7288
8aee397
ae6509f
97a985d
4e95482
eddcfc8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,8 @@ | |
| // Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
|
||
| using System.IO; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
|
|
||
| using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute; | ||
| using Encoding = System.Text.Encoding; | ||
|
|
@@ -267,6 +269,42 @@ public static XDocument Load(Stream stream, LoadOptions options) | |
| } | ||
| } | ||
|
|
||
| /// <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. | ||
|
|
@@ -314,6 +352,42 @@ public static XDocument Load(TextReader textReader, LoadOptions options) | |
| } | ||
| } | ||
|
|
||
| /// <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"/>. | ||
|
|
@@ -350,6 +424,55 @@ public static XDocument Load(XmlReader reader, LoadOptions options) | |
| { | ||
| if (reader == null) throw new ArgumentNullException("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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please put the throw statement on its own line to match the coding guidelines. |
||
| 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 async Task<XDocument> LoadAsync(XmlReader reader, LoadOptions options, CancellationToken cancellationToken) | ||
| { | ||
| if (reader == null) throw new ArgumentNullException("reader"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please put the throw statement on its own line to match the coding guidelines.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should really be part of its own non-async method that then delegates to an async method for the actual work so that the usage error propagates out synchronously. |
||
| if (reader.ReadState == ReadState.Initial) | ||
| { | ||
| cancellationToken.ThrowIfCancellationRequested(); | ||
| await reader.ReadAsync().ConfigureAwait(false); | ||
| } | ||
|
|
||
| XDocument d = InitLoad(reader, options); | ||
| await d.ReadContentFromAsync(reader, options, cancellationToken); | ||
|
|
||
| if (!reader.EOF) throw new InvalidOperationException(SR.InvalidOperation_ExpectedEndOfFile); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please put the throw statement on its own line to match the coding guidelines. |
||
| 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) | ||
| { | ||
|
|
@@ -371,9 +494,6 @@ public static XDocument Load(XmlReader reader, LoadOptions options) | |
| { | ||
| 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; | ||
| } | ||
|
|
||
|
|
@@ -478,6 +598,40 @@ public void Save(Stream stream, SaveOptions options) | |
| } | ||
| } | ||
|
|
||
| /// <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) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we catching ArgumentException? That is generally not a good idea.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After looking at the documentation I see that what we throw if the encoding cannot be found and you are doing what we already do in Save. While I don't particularly like this approach I also don't see another option so I guess we will have to live with this. |
||
| { | ||
| } | ||
| } | ||
|
|
||
| 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> | ||
|
|
@@ -516,6 +670,29 @@ public void Save(TextWriter textWriter, SaveOptions options) | |
| } | ||
| } | ||
|
|
||
| /// <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); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Output this <see cref="XDocument"/> to an <see cref="XmlWriter"/>. | ||
| /// </summary> | ||
|
|
@@ -527,6 +704,19 @@ public void Save(XmlWriter writer) | |
| WriteTo(writer); | ||
| } | ||
|
|
||
| /// <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 async Task SaveAsync(XmlWriter writer, CancellationToken cancellationToken) | ||
| { | ||
| await WriteToAsync(writer, cancellationToken).ConfigureAwait(false); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Output this <see cref="XDocument"/>'s underlying XML tree to the | ||
|
|
@@ -556,6 +746,42 @@ public override void WriteTo(XmlWriter writer) | |
| 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 async Task WriteToAsync(XmlWriter writer, CancellationToken cancellationToken) | ||
| { | ||
| if (writer == null) throw new ArgumentNullException("writer"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please put the throw statement on its own line to match the coding guidelines. |
||
|
|
||
| cancellationToken.ThrowIfCancellationRequested(); | ||
|
|
||
| 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); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put the throw statement on its own line to match the coding guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The single-line test/throw style in my patch is consistent with existing XLINQ code. Do you still prefer me to use the new guidelines within my patch, or should we hold off style changes for another PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please ignore my comments on the one-line if statements as you are correct all this code still needs to be run through our formatting tool, we have issue https://github.com/dotnet/corefx/issues/496 tracking that.