【问题标题】:How to read the text element of an XML node without dereferencing entities using XmlReader如何在不使用 XmlReader 取消引用实体的情况下读取 XML 节点的文本元素
【发布时间】:2015-05-08 16:07:47
【问题描述】:

我正在尝试读取包含如下所述数据的元素的 XML 文档。

通过reader.Valuereader.ReadContentAsString()reader.ReadContentAsObject() 访问文本节点会导致读取的值被截断为最后一个&,因此对于下面的数据,这将是 ISO^urn:ihe:iti: xds:2013:推荐。使用XmlDocument 可以正确读取文本节点,所以我假设必须有一种方法也可以使用阅读器来完成这项工作。

 <Slot name="urn:ihe:iti:xds:2013:referenceIdList">
              <ValueList>
                <Value>123456^^^&amp;orgID&amp;ISO^urn:ihe:iti:xds:2013:referral</Value>
                <Value>098765^^^&amp;orgID&amp;ISO^urn:ihe:iti:xds:2013:referral</Value>
              </ValueList>
            </Slot>


澄清编辑

在提出问题后,我能够确定我的问题来自于从在 WCF 服务调用的上下文中执行的 MessageBuffer 创建的 XPathNavigator 实例创建 XmlReader。因此@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

【问题讨论】:

    标签: c# xml wcf c#-4.0 xmlreader


    【解决方案1】:

    回答: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^^^&amp;orgID&amp;ISO^urn:ihe:iti:xds:2013:referral</Value>
            <Value>098765^^^&amp;orgID&amp;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);
      }
    }
    

    【讨论】:

    • 仅供参考,您不应使用new XmlTextReader()new XmlTextWriter()。自 .NET 2.0 以来,它们已被弃用。请改用XmlReader.Create()XmlWriter.Create()
    • 不幸的是,这不是我所看到的行为。更准确地说,reader.value 在 linqpad 或 MSTest 中运行时有效,但在 WCF 服务调用的上下文中运行时会截断。
    • @Tedford 也许问题在于数据中的编码或不可读的符号?做一个有错误的简单例子。
    • 我找到了解决问题的方法。这是使用 XmlReader 的一个极端案例,因此我会将这个解决方案标记为对于 99% 的案例是正确的,并发布我的解决方案以解决小众错误。
    【解决方案2】:

    我的问题最终过于宽泛,因为不正确的行为(使用 reader.Value 时截断)仅在代码在 WCF 调用的上下文中执行时才会出现。从单元测试中执行包含类的逻辑时,它工作得非常好。

    所以突出的设置可以复制如下

    失败的代码

    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
    

    创建此读取器实例后,当文本包含字符实体引用时,从它读取的任何 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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-05
      • 2017-09-10
      • 2021-06-20
      • 2011-07-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多