Full Content Reads Using Character Streams

The methods ReadChars, ReadBinHex, ReadBase64 are used to read large streams. The difference is that the ReadChars method reads the text as it is (US-ASCII), the ReadBase64 method decodes Base64-encoded text, while the ReadBinHex method decodes binhex-encoded data. This is useful if the XML contains international text, images, or video that have been encoded.

The methods perform as follows:

  • ReadChars, ReadBinHex and ReadBase64 are only available on an element. Using these methods on other node types does nothing.
  • The actual character content of the buffer is returned. There is no attempt to resolve entities, CDATA or any other markup within the buffer. It returns everything between the start tag and the end tag, including any markup, just as if you were reading off the stream.
  • Normalization settings are not honored. There is no normalization.
  • ReadChars returns the value "0" when it has reached the end of the character stream it was operating on, and the reader is positioned at the same place as if the application had called ReadInnerXml.
  • All attribute Read methods, like ReadAttributeValue, have no operation while reading from the stream using ReadChars.

Sample code of ReadBase64:

This method decodes Base64 and returns the decoded binary bytes.

Dim str As String = "<ROOT>AQID</ROOT>"
Dim r As New XmlTextReader(New StringReader(str))

r.Read()
Dim buffer(1) As Byte
While r.ReadBase64(buffer, 0, 1) <> 0
   Console.Write(buffer(0))
End While
Console.WriteLine()

[C#]
string str = "<ROOT>AQID</ROOT>";
XmlTextReader r = new XmlTextReader(new StringReader(str));

r.Read();
byte[] buffer = new byte[1];
while(r.ReadBase64(buffer,0,1) != 0) {
   Console.Write(buffer[0]);
}
Console.WriteLine();

For an additional code sample, see XmlTextReader.ReadBase64.

Sample code of ReadBinHex:

This is the "wellform.xml" input to the ReadBinHex sample.

wellform.xml

<dt:person xmlns:dt="urn1">
<name>Alice Smith</name>
<dt:address>123 Maple Street, Seattle, WA 98112</dt:address>
<phone>(206) 555-1234</phone>
<!-- The following element is optional -->
<comments>The lady with the overgrown lawn.</comments>
<dt:date>2000-07-06</dt:date>
<time>18:31:40</time>
<dt:BinHex>000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF</dt:BinHex>
<Base64>AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==</Base64>
</dt:person>

This method decodes BinHex and returns the decoded binary bytes.

Private Sub TestIncrementalReadBinHex()
   Dim xmlReader As New XmlTextReader("wellform.xml")
   Dim i As Integer
   Try
      Dim binhexlen As Integer = 0
      Dim binhex(1000) As Byte
      While xmlReader.Read()
         If "dt:BinHex" = xmlReader.Name Then
            Exit While
         End If
      End While
      binhexlen = xmlReader.ReadBinHex(binhex, 0, 50)
      For i = 0 To binhexlen - 1
         Console.Write(binhex(i))
      Next i
      While "dt:BinHex" = xmlReader.Name
         binhexlen = xmlReader.ReadBinHex(binhex, 0, 50)
         For i = 0 To binhexlen - 1
            Console.Write(binhex(i))
         Next i
      End While
      Console.WriteLine()
      xmlReader.Close()
   Catch e As Exception
      xmlReader.Close()
      Console.WriteLine(("Exception: " & e.Message))
      Return
   End Try
End Sub
[C#]
private void TestIncrementalReadBinHex() {       
   XmlTextReader xmlReader   = new XmlTextReader("wellform.xml");
   try {
      int binhexlen = 0;
      byte[] binhex = new byte[1000];
      while (xmlReader.Read()) {
         if ("dt:BinHex" == xmlReader.Name) break;
      }
      binhexlen = xmlReader.ReadBinHex(binhex, 0, 50);
      for (int i=0; i < binhexlen; i++) Console.Write(binhex[i]);
      while ("dt:BinHex" == xmlReader.Name) {
         binhexlen = xmlReader.ReadBinHex(binhex, 0, 50);
         for (int i=0; i < binhexlen; i++) Console.Write(binhex[i]);
      }
      Console.WriteLine();
      xmlReader.Close();
   }
   catch(Exception e) {
      xmlReader.Close();
      Console.WriteLine("Exception: " + e.Message);
      return;
   }
}

For an additional code sample, see XmlTextReader.ReadBinHex

Sample of ReadChars

If you are positioned on the Item element node in the following XML:

<Item>test</Item>

then ReadChars returns "test" and positions the reader on the node that follows </Item> EndElement. Given this XML input:

...
<small>
   <time>
      <days> 30 </days>
      <hours> 3 </hours>
      <minutes> 30 </minutes>
   </time>
</small>
<big>
...

executing this code against it, the application finds that when in the while loop, the current position is at the <small> tag and at the end of the loop, the current position is at the <big> tag:

If XmlNodeType.Element = reader.NodeType And "small" = reader.Name Then
   While 0 <> reader.ReadChars(buffer, 0, 1)
      ' Do something;
      ' reader is now positioned at <small>. Attribute values may not be
      ' available at this point. 
   End While 
End If
' At this point the Reader is positioned at <big > tag.
[C#]
if (XmlNodeType.Element == reader.NodeType && "small" == reader.Name) {
    while(0 != reader.ReadChars(buffer, 0, 1)) {
        // Do something;
        // reader is now positioned at <small>. Attribute values may not
       // be available at this point. 
    }
}
// At this point the Reader is positioned at <big > tag.

If you do not want to read all the way to the end of ReadChars, the Read method can be called in the middle and the reader is positioned after the end element. In the previous code, this would be the <big> tag.

Successive calls to ReadChars advances the reader through the text. The following table shows what occurs, given the data <Item>test</Item> and calling the methods successively.

Method calls Results
First call: ReadChars(buf, 0, 2) Returns 2, and buf contains "te".
Second call: ReadChars(buf, 0, 2) Returns 2, and buf contains "st".
Third call: ReadChars(buf, 0, 2) Returns 0.

The ReadChars method ignores XML markup that is not well-formed. For example, the following XML input is not well-formed.

<A>a<A>g</A>

Using the ReadChars method against this input returns markup only from one pair of tags, and any remaining markup is ignored. This means that a ReadChars issued against the input would return:

a<A>g</A>

See Also

Reading XML with the XmlReader | Document Type Declaration Information | Handling White Space with XmlTextReader | Attribute Value Normalization | Exception Handling using XmlException in XmlTextReader | XmlReader Class | XmlReader Members | XmlNodeReader Class | XmlNodeReader Members | XmlTextReader Class | XmlTextReader Members | XmlValidatingReader Class | XmlValidatingReader