Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to save the current XMLReader Position for later use?

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.

like image 434
JavaSa Avatar asked Dec 22 '12 12:12

JavaSa


People also ask

How does XmlReader work?

XmlReader provides forward-only, read-only access to XML data in a document or stream. This class conforms to the W3C Extensible Markup Language (XML) 1.0 (fourth edition) and the Namespaces in XML 1.0 (third edition) recommendations. XmlReader methods let you move through XML data and read the contents of a node.

How does XmlReader work in C#?

C# XmlReader ReadThe Read method reads the next node from the stream. In this XML file, we have products. The example presents the classic approach to reading XML files. We read the document node by node and in the switch statement or expression deal with the particular element, text, attribute or other type of node.

What is the purpose of IsStartElement () which is instance method of XmlTextReader class?

IsStartElement(String) Calls MoveToContent() and tests if the current content node is a start tag or empty element tag and if the Name property of the element found matches the given argument.

What does XmlReader create FS do?

Creates a new XmlReader instance using the specified stream with default settings. Creates a new XmlReader instance by using the specified URI and settings.


1 Answers

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.

like image 198
Jose M. Avatar answered Sep 18 '22 22:09

Jose M.