简体   繁体   中英

How to read the text element of an XML node without dereferencing entities using XmlReader

I am attempting to read a XML document containing elements like the data mentioned below.

Accessing the text node via reader.Value , reader.ReadContentAsString() , reader.ReadContentAsObject() results in the value read being truncated to the last ampersand, so in the case of the data below that would be ISO^urn:ihe:iti:xds:2013:referral. Using XmlDocument the text nodes can be read properly so I am assuming there has to be a way to make this work using the reader as well.

 <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>


Clarification Edit

After asking the question I was able to determine my issue came from creating an XmlReader from a XPathNavigator instance created from a MessageBuffer executing in the context of a WCF service call. Thus @DarkGray's answer was correct for the original question but did not really address the root of the problem. I provided a second answer which addressed my corner case.

 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 

Answer: reader.Value

Output:

123456^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral
098765^^^&orgID&ISO^urn:ihe:iti:xds:2013:referral

Example:

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);
  }
}

My question ended up being too broad as the incorrect behavior (truncation when using reader.Value ) only manifest when the code was executing within the context of a WCF call. It worked perfectly fine when exercising the logic of the containing class from a unit test.

So the salient setup can be reproduced as follows

The Failing Code

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

Once this reader instance was created then any XmlText node read from it produced the truncated value when the text contained an character entity reference. The only way I found that allow for the original value to be read in high-fidelity was to eschew the use of the XPathNavigator completely and instead take the hit of creating another Message instance. Note, the fix uses the long way around to write the SOAP envelope to the stream as affected service is using MTOM encoding. Writing to the stream directly from the MessageBuffer resulted in the MIME fences being written out.

The Fix

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
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM