如何在不使用 XmlReader 取消引用实体的情况下读取 XML 节点的文本元素
How to read the text element of an XML node without dereferencing entities using XmlReader
我正在尝试阅读一份 XML 文档,其中包含如下所述的数据等元素。
通过 reader.Value
、reader.ReadContentAsString()
、reader.ReadContentAsObject()
访问文本节点会导致读取的值被截断为最后一个 & 符号,因此对于下面的数据,这将是ISO^urn:ihe:iti:xds:2013:推荐。使用 XmlDocument
可以正确读取文本节点,所以我假设必须有一种方法可以使用 reader 来完成这项工作。
<Slot name="urn:ihe:iti:xds:2013:referenceIdList">
<ValueList>
<Value>123456^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral</Value>
<Value>098765^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral</Value>
</ValueList>
</Slot>
澄清编辑
在问了这个问题后,我能够确定我的问题来自于从 XPathNavigator
创建的 XmlReader
实例,该实例是在 WCF 服务调用的上下文中执行的 MessageBuffer
.因此@DarkGray 的回答对于原始问题是正确的,但并没有真正解决问题的根源。我提供了第二个答案来解决我的极端情况。
System.ServiceModel.Channels.Message message; // the inbound SOAP message
var buffer = message.CreateBufferedCopy(11 * 1024 * 1024);
var navigator = buffer.CreateNavigator();
var reader = navigator.ReadSubtree();
// advance the reader to the text element
//
// `reader.Value` now produces ISO^urn:ihe:iti:xds:2013:referral
答案:reader.Value
输出:
123456^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral
098765^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral
示例:
public static void Execute()
{
var xml = @"
<Slot name='urn:ihe:iti:xds:2013:referenceIdList'>
<ValueList>
<Value>123456^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral</Value>
<Value>098765^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral</Value>
</ValueList>
</Slot>
";
var reader = System.Xml.XmlReader.Create(new System.IO.StringReader(xml));
for (; ; )
{
if (!reader.Read())
break;
if (reader.NodeType == System.Xml.XmlNodeType.Text)
Console.WriteLine(reader.Value);
}
}
我的问题最终变得过于宽泛,因为不正确的行为(使用 reader.Value
时截断)仅在代码在 WCF 调用的上下文中执行时才会出现。在单元测试中执行包含 class 的逻辑时,它工作得非常好。
所以显着的设置可以重现如下
失败的代码
System.ServiceModel.Channels.Message message; // the inbound SOAP message
var buffer = message.CreateBufferedCopy(11 * 1024 * 1024);
var navigator = buffer.CreateNavigator();
var reader = navigator.ReadSubtree();
// advance the reader to the text element
//
// `reader.Value` now produces ISO^urn:ihe:iti:xds:2013:referral
创建此 reader 实例后,当文本包含字符实体引用时,从中读取的任何 XmlText 节点都会生成截断值。我发现允许以高保真度读取原始值的唯一方法是完全避免使用 XPathNavigator,而是采取创建另一个 Message
实例的方法。请注意,由于受影响的服务正在使用 MTOM 编码,因此修复使用了很长的方法将 SOAP 信封写入流。直接从 MessageBuffer 写入流导致 MIME 栅栏被写出。
修正
System.ServiceModel.Channels.Message message; // the inbound SOAP
var buffer = message.CreateBufferedCopy(MaxMessageSize);
var message = buffer.CreateMessage();
using (MemoryStream stream = new MemoryStream())
using (XmlWriter writer = XmlWriter.Create(stream))
{
message.WriteMessage(writer);
writer.Flush();
stream.Position = 0;
using (XmlReader reader = XmlReader.Create(stream))
{
// business logic goes here
}
}
我正在尝试阅读一份 XML 文档,其中包含如下所述的数据等元素。
通过 reader.Value
、reader.ReadContentAsString()
、reader.ReadContentAsObject()
访问文本节点会导致读取的值被截断为最后一个 & 符号,因此对于下面的数据,这将是ISO^urn:ihe:iti:xds:2013:推荐。使用 XmlDocument
可以正确读取文本节点,所以我假设必须有一种方法可以使用 reader 来完成这项工作。
<Slot name="urn:ihe:iti:xds:2013:referenceIdList">
<ValueList>
<Value>123456^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral</Value>
<Value>098765^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral</Value>
</ValueList>
</Slot>
澄清编辑
在问了这个问题后,我能够确定我的问题来自于从 XPathNavigator
创建的 XmlReader
实例,该实例是在 WCF 服务调用的上下文中执行的 MessageBuffer
.因此@DarkGray 的回答对于原始问题是正确的,但并没有真正解决问题的根源。我提供了第二个答案来解决我的极端情况。
System.ServiceModel.Channels.Message message; // the inbound SOAP message
var buffer = message.CreateBufferedCopy(11 * 1024 * 1024);
var navigator = buffer.CreateNavigator();
var reader = navigator.ReadSubtree();
// advance the reader to the text element
//
// `reader.Value` now produces ISO^urn:ihe:iti:xds:2013:referral
答案:reader.Value
输出:
123456^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral
098765^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral
示例:
public static void Execute()
{
var xml = @"
<Slot name='urn:ihe:iti:xds:2013:referenceIdList'>
<ValueList>
<Value>123456^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral</Value>
<Value>098765^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral</Value>
</ValueList>
</Slot>
";
var reader = System.Xml.XmlReader.Create(new System.IO.StringReader(xml));
for (; ; )
{
if (!reader.Read())
break;
if (reader.NodeType == System.Xml.XmlNodeType.Text)
Console.WriteLine(reader.Value);
}
}
我的问题最终变得过于宽泛,因为不正确的行为(使用 reader.Value
时截断)仅在代码在 WCF 调用的上下文中执行时才会出现。在单元测试中执行包含 class 的逻辑时,它工作得非常好。
所以显着的设置可以重现如下
失败的代码
System.ServiceModel.Channels.Message message; // the inbound SOAP message
var buffer = message.CreateBufferedCopy(11 * 1024 * 1024);
var navigator = buffer.CreateNavigator();
var reader = navigator.ReadSubtree();
// advance the reader to the text element
//
// `reader.Value` now produces ISO^urn:ihe:iti:xds:2013:referral
创建此 reader 实例后,当文本包含字符实体引用时,从中读取的任何 XmlText 节点都会生成截断值。我发现允许以高保真度读取原始值的唯一方法是完全避免使用 XPathNavigator,而是采取创建另一个 Message
实例的方法。请注意,由于受影响的服务正在使用 MTOM 编码,因此修复使用了很长的方法将 SOAP 信封写入流。直接从 MessageBuffer 写入流导致 MIME 栅栏被写出。
修正
System.ServiceModel.Channels.Message message; // the inbound SOAP
var buffer = message.CreateBufferedCopy(MaxMessageSize);
var message = buffer.CreateMessage();
using (MemoryStream stream = new MemoryStream())
using (XmlWriter writer = XmlWriter.Create(stream))
{
message.WriteMessage(writer);
writer.Flush();
stream.Position = 0;
using (XmlReader reader = XmlReader.Create(stream))
{
// business logic goes here
}
}