11

I have created an XMLReader object out of a Stream object which I was written to earlier by XMLWriter object.

I know XMLReader object is forward only and therefore I want to be able to save current reading position, so I will be able to continue read just from the place I stopped reading.

Is it possible?
I know it is maybe tricky, as XMLreader read chunks of memory blocks so maybe it will be a problem to restore current XML element reading point.

Please advice only if you know for sure, it will work from your experience with this issue specifically.

Note :
1. I thought of simply saving the whole XMLReader object reference for that scenario.
2. XMLReader Position = current pointer to reading element not Stream.Position as it is something else.

Picrofo Software
  • 5,475
  • 3
  • 23
  • 37
JavaSa
  • 5,813
  • 16
  • 71
  • 121
  • Have you tried setting the `Stream.Position` property before using the `XMLReader`? That ought to work. – Steven Doggart Dec 22 '12 at 12:55
  • Yes I did, Stream has kind of weird position which apparently cannot be translated back to specific reading point element in Xml – JavaSa Dec 22 '12 at 13:01
  • Right, but if you get the `Stream.Position` and then set it back to that same position before you give it to a new `XMLReader`, it should pick up from the same place. – Steven Doggart Dec 22 '12 at 13:03
  • I think I've been trying that(I was trying many things) and didn't work. Have you managed to see it is working when you worked with it ? – JavaSa Dec 22 '12 at 13:12
  • No, I'm at my mac at the moment, so I can't try it easily, but I'd be very surprised if it didn't work. – Steven Doggart Dec 22 '12 at 13:13
  • 2
    This might help: http://stackoverflow.com/questions/2160533/getting-the-current-position-from-an-xmlreader – U1199880 Dec 22 '12 at 15:44
  • @U1199880 Well, that explains why the stream's position won't work :) Nice link. – Steven Doggart Dec 22 '12 at 16:39
  • @StevenDoggart: Just out of curiosity , do you think there is a way to do it somehow? Or it is kind of a dead end? – JavaSa Dec 22 '12 at 17:42
  • Anyway if you don't know , it's ok because it is not urgent anymore as I chose another approach with XMLDocument from our other post :). – JavaSa Dec 22 '12 at 17:45
  • 2
    Yes, it looks like perhaps the best you could do would be to get the line number from the `XmlTextReader`, then, when you open the stream the next time, loop through each line in the stream until you reach that line number. It wouldn't be pretty, but it seems like that's the best option available. – Steven Doggart Dec 22 '12 at 17:55

1 Answers1

1

I work in a project where an external system writes xmls (without a defined namespace) and we need to read them to find nodes with some special values:

  • When the value is not ready, we read again after a few minutes.
  • In other case, we process the node (attributes, values, etc.)

So, I think this code can help you:

var input1 = @"<root>
 <ta>
   <XGLi6id90>774825484.1418393</XGLi6id90>
   <VAfrBVB>
     <EG60sk>1030847709.7303829</EG60sk>
     <XR>NOT_READY</XR>
   </VAfrBVB>
 </ta>
 <DxshpR>1123</DxshpR>

var input2 = @"<root>
 <ta>
   <XGLi6id90>774825484.1418393</XGLi6id90>
   <VAfrBVB>
     <EG60sk>1030847709.7303829</EG60sk>
     <XR>99999999</XR>
   </VAfrBVB>
 </ta>
 <DxshpR>1123</DxshpR>

var stream1 = new MemoryStream(Encoding.UTF8.GetBytes(input1));
var stream2 = new MemoryStream(Encoding.UTF8.GetBytes(input2));
stream1.Position = 0;
stream2.Position = 0;

var position1 = DoWork(stream1, new Position());
var position2 = DoWork(stream2, position1);

    public static Position DoWork(Stream stream, Position position)
    {
        using (XmlTextReader xmlTextReader = new XmlTextReader(stream))
        {
            using (XmlReader xmlReader = XmlReader.Create(xmlTextReader, xmlReaderSettings))
            {
                // restores the last position 
                xmlTextReader.SetPosition(position);

                System.Diagnostics.Debug.WriteLine(xmlReader.Value); // Second time prints 99999999

                while (xmlReader.Value != "NOT_READY" && xmlReader.Read())
                {
                    // a custom logic to process nodes....
                }

                // saves the position to process later ...
                position = xmlTextReader.GetPosition();

                System.Diagnostics.Debug.WriteLine(xmlReader.Value); // First time prints NOT_READY
            }

        }

        return position;
    }
}

public class Position
{
    public int LinePosition { get; set; }
    public int LineNumber { get; set; }
}

public static class XmlReaderExtensions
{
    public static void SetPosition(this XmlTextReader xmlTextReader, Position position)
    {
        if (position != null)
        {
            while (xmlTextReader.LineNumber < position.LineNumber && xmlTextReader.Read())
            {
            }

            while (xmlTextReader.LinePosition < position.LinePosition && xmlTextReader.Read())
            {
            }
        }
    }

    public static Position GetPosition(this XmlTextReader xmlTextReader)
    {
        Position output;

        if (xmlTextReader.EOF)
        {
            output = new Position();
        }
        else
        {
            output = new Position { LineNumber = xmlTextReader.LineNumber, LinePosition = xmlTextReader.LinePosition };
        }

        return output;
    }
}

Important and obviously, it will work only when the structure of the xml (line breaks, nodes, etc.) is always the same. In other case, it will not work.

Jose M.
  • 1,296
  • 17
  • 22