![](/img/trans.png)
[英]XMLWriter - setting DoNotEscapeUriAttributes and OutputMethod
[英]XmlWriter Async operations fail with XmlWriterSettings.OutputMethod = Html
使用XmlWriterSettings.OutputMethod = OutputMethod.Html
創建XmlWriter
時,異步操作失敗。 當使用OutputMethod.AutoDetect
(默認)創建相同的內容時,異步操作成功。
失敗的代碼(帶小提琴):
var transform = new XslCompiledTransform();
using var reader = XmlReader.Create(new StringReader(@"
<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">
<xsl:output method=""html"" indent=""yes"" doctype-system=""html""/>
<xsl:template match=""/"">
<bar/>
</xsl:template>
</xsl:stylesheet>"));
transform.Load(reader);
var settings = transform.OutputSettings.Clone();
settings.CloseOutput = false;
settings.Async = true;
using var stream = new MemoryStream();
using (var writer = XmlWriter.Create(stream, settings))
{
await writer.WriteStartDocumentAsync();
await writer.WriteStartElementAsync(null, "foo", null);
await writer.WriteEndElementAsync();
await writer.WriteEndDocumentAsync();
}
stream.Position = 0;
var content = new StreamReader(stream).ReadToEnd();
Assert.Contains("foo", content);
使用堆棧跟蹤:
Message:
System.NotImplementedException : The method or operation is not implemented.
Stack Trace:
XmlWriter.WriteStartElementAsync(String prefix, String localName, String ns)
XmlWellFormedWriter.WriteStartElementAsync_NoAdvanceState(String prefix, String localName, String ns)
XmlWellFormedWriter.WriteStartElementAsync(String prefix, String localName, String ns)
XmlAsyncCheckWriter.WriteStartElementAsync(String prefix, String localName, String ns)
工作代碼(帶工作小提琴):
var settings = new XmlWriterSettings();
settings.CloseOutput = false;
settings.Async = true;
using var stream = new MemoryStream();
using (var writer = XmlWriter.Create(stream, settings))
{
await writer.WriteStartDocumentAsync();
await writer.WriteStartElementAsync(null, "foo", null);
await writer.WriteEndElementAsync();
await writer.WriteEndDocumentAsync();
}
stream.Position = 0;
var content = new StreamReader(stream).ReadToEnd();
Assert.Contains("foo", content);
在調試模式下檢查各種東西,兩條代碼路徑似乎都在后台使用System.Xml.XmlAsyncCheckWriter
。
有趣的是,造成這種情況的不是OutputMethod
,而是doctype-system
。 刪除該屬性,您的異步調用將神奇地工作。
我可以告訴你發生了什么,但不能告訴你為什么他們選擇這樣做。
首先,編寫器由XmlWriterSettings.CreateWriter(Stream)創建。 剪掉所有的絨毛,它是這樣的:
internal XmlWriter CreateWriter(Stream output)
{
XmlWriter writer;
if (Encoding.WebName == "utf-8") {
switch (OutputMethod) {
case XmlOutputMethod.Html:
writer= new HtmlUtf8RawTextWriter(output, this);
break;
}
}
// Wrap with Xslt/XQuery specific writer if needed;
// XmlOutputMethod.AutoDetect writer does this lazily when it creates the underlying Xml or Html writer.
if (OutputMethod != XmlOutputMethod.AutoDetect) {
if (IsQuerySpecific) {
// Create QueryOutputWriter if CData sections or DocType need to be tracked
writer = new QueryOutputWriter((XmlRawWriter)writer, this);
}
}
// wrap with well-formed writer
writer = new XmlWellFormedWriter(writer, this);
if (_useAsync)
writer = new XmlAsyncCheckWriter(writer);
return writer;
}
所以最后,你會得到一層洋蔥/食人魔
XmlAsyncCheckWriter(
XmlWellFormedWriter(
QueryOutputWriter(
HtmlUtf8RawTextWriter)))
當您進行Write...Async()
調用時,您會期望它從外部 Writer a 一直級聯到HtmlUtf8RawTextWriter
中的最深級別 - 它確實具有您想要的異步調用。
不幸的是, QueryOutputWriter包裝器不會將 Async 調用委托給內部編寫器,實際上是NotImplementedException
的那個。 它是一個錯誤嗎? 還是深思熟慮的選擇? 我不知道。
如果您不需要 DOCTYPE,並且不在 output 中使用 CDATA(兩者都由我們有問題的QueryOutputWriter
處理),只需從 XSL 中刪除doctype-system
即可解決您的問題。 這將導致以下IsQuerySpecific
為false
,從而防止不需要的包裝。
private bool IsQuerySpecific =>
CDataSectionElements.Count != 0
|| _docTypePublic != null
|| _docTypeSystem != null
|| _standalone == XmlStandalone.Yes;
...
if (IsQuerySpecific)
xmlWriter = new QueryOutputWriter((XmlRawWriter)xmlWriter, this);
如果您確實需要 DOCTYPE/CDATA,那么重新實現一些層並覆蓋函數將是一個有趣的練習。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.