Is there a way to get the current position in the stream of the node under examination by the XmlReader?
I'd like to use the XmlReader to parse a document and save the position of certain elements so that I can seek to them later.
Addendum:
I'm getting Xaml generated by a WPF control. The Xaml should not change frequently. There are placeholders in the Xaml where I need to replace items, sometimes looping. I thought it might be easier to do in code rather than a transform (I might be wrong about this). My idea was to parse it to a simple data structure of what needs to be replace and where it is, then use a StringBuilder to produce the final output by copying chunks from the xaml string.
As Jon Skeet says,
XmlTextReader
implementsIXmlLineInfo
butXmlTextReader
was deprecated since.NET 2.0
and the question is aboutXmlReader
only. I found this solution:P.S. Tested for .NET Compact Framework 3.5, but should work for others too.
I have worked on a solution for this, and while it may not work in every scenario and uses reflection against private members of .NET Framework classes, I am able to calculate the correct position of the
XmlReader
with the extension method shown below.Your
XmlReader
must be created from aStreamReader
using an underlyingFileStream
(I haven't tried otherStreams
, and they may work as well so long as they report their position).I've posted details here: http://g-m-a-c.blogspot.com/2013/11/determine-exact-position-of-xmlreader.html
I have the same problem and apparently there is no simple solution.
So I decided to manipulate two read-only FileStream : one for the XmlReader, the other to get the position of each line :
This is not the best way of doing this because it uses two readers. To avoid this, we could rewrite a new FileReader shared between the XmlReader and the line counter. But it simply gives you the offset of the line you're interested in. To get the exact offset of the tag, we should use LinePosition, but this can be tricky because of the Encoding.
Just to head off one suggestion before it's made: you could keep a reference to the underlying stream you pass into
XmlReader
, and make a note of its position - but that will give you the wrong results, as the reader will almost certainly be buffering its input (i.e. it'll read the first 1024 characters or whatever - so your first node might "appear" to be at character 1024).If you use
XmlTextReader
instead of justXmlReader
, then that implementsIXmlLineInfo
, which means you can ask for theLineNumber
andLinePosition
at any time - is that good enough for you? (You should probably checkHasLineInfo()
first, admittedly.)EDIT: I've just noticed that you want to be able to seek to that position later... in that case line information may not be terribly helpful. It's great for finding something in a text editor, but not so great for moving a file pointer. Could you give some more information about what you're trying to do? There may be a better way of approaching the problem.
Thanks Geoff for the answer. It worked perfectly on windows 7. But somehow with .net 4 version on windows server 2003 of mscorlib.dll, i had to change following 2 functions to work.
Also underlyingStreamReader in GetPosition method should be peek to advance the pointer.