創建XmlWriterwith 時XmlWriterSettings.OutputMethod = OutputMethod.Html,異步操作失敗。創建與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。
uj5u.com熱心網友回復:
有趣的是,這不是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包裝器不會將異步呼叫委托給內部撰寫器,實際上是拋出NotImplementedException. 這是一個錯誤嗎?還是刻意的選擇?我不知道。
如果您不需要 DOCTYPE,并且不在您的輸出中使用 CDATA(兩者都由我們的問題處理QueryOutputWriter),只需doctype-system從您的 XSL 中洗掉 即可解決您的問題。這將導致以下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,那么重新實作某些層并覆寫函式將是一個有趣的練習。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/365394.html
上一篇:XSLT-添加新元素和值
下一篇:XSLT洗掉具有組合條件的節點
