有没有办法在XmlReader检查的节点流中获取当前位置?
我想使用XmlReader来解析文档并保存某些元素的位置,以便我以后可以查找它们.
附录:
我正在通过WPF控件生成Xaml.Xaml不应经常更改.在Xaml中有占位符,我需要替换项目,有时循环.我认为在代码中而不是转换可能更容易(我可能错了).我的想法是将其解析为需要替换的简单数据结构及其位置,然后使用StringBuilder通过复制xaml字符串中的块来生成最终输出.
小智 9
正如Jon Skeet所说,XmlTextReader实现IXmlLineInfo但是XmlTextReader从那时起就被弃用.NET 2.0了,问题只是关于XmlReader.我找到了这个解决方案
XmlReader xr = XmlReader.Create( // MSDN recommends to use Create() instead of ctor()
new StringReader("<some><xml><string><data>"),
someSettings // furthermore, can't set XmlSettings on XmlTextReader
);
IXmlLineInfo xli = (IXmlLineInfo)xr;
while (xr.Read())
{
// ... some read actions ...
// current position in StringReader can be accessed through
int line = xli.LineNumber;
int pos = xli.LinePosition;
}
Run Code Online (Sandbox Code Playgroud)
PS针对.NET Compact Framework 3.5进行了测试,但也应该适用于其他人.
只是在它出现之前提出一个建议:你可以保留对你传入的基础流的引用XmlReader,并记下它的位置 - 但这会给你错误的结果,因为读者几乎肯定会缓冲它的输入(即它会读取前1024个字符或其他任何内容 - 因此您的第一个节点可能"显示"为字符1024).
如果使用XmlTextReader,而不只是XmlReader,然后实现IXmlLineInfo,这意味着你可以要求LineNumber和LinePosition在任何时候-就是对你不够好?(HasLineInfo()诚然,你应该先检查一下.)
编辑:我刚刚注意到你希望以后能够找到那个位置......在这种情况下,行信息可能不会非常有用.它非常适合在文本编辑器中查找内容,但对于移动文件指针却不是那么好.你能提供一些关于你想做什么的更多信息吗?可能有更好的方法来解决问题.
我已经为此开发了一个解决方案,虽然它可能无法在每个场景中使用并且使用针对.NET Framework类的私有成员的反射,但我能够XmlReader使用下面显示的扩展方法计算正确的位置.
你XmlReader必须StreamReader使用底层创建FileStream(我没有尝试过其他的Streams,只要他们报告他们的位置,他们也可以工作).
我在这里发布了详细信息:http://gmac.blogspot.com/2013/11/determine-exact-position-of-xmlreader.html
public static class XmlReaderExtensions
{
private const long DefaultStreamReaderBufferSize = 1024;
public static long GetPosition(this XmlReader xr, StreamReader underlyingStreamReader)
{
// Get the position of the FileStream
long fileStreamPos = underlyingStreamReader.BaseStream.Position;
// Get current XmlReader state
long xmlReaderBufferLength = GetXmlReaderBufferLength(xr);
long xmlReaderBufferPos = GetXmlReaderBufferPosition(xr);
// Get current StreamReader state
long streamReaderBufferLength = GetStreamReaderBufferLength(underlyingStreamReader);
int streamReaderBufferPos = GetStreamReaderBufferPos(underlyingStreamReader);
long preambleSize = GetStreamReaderPreambleSize(underlyingStreamReader);
// Calculate the actual file position
long pos = fileStreamPos
- (streamReaderBufferLength == DefaultStreamReaderBufferSize ? DefaultStreamReaderBufferSize : 0)
- xmlReaderBufferLength
+ xmlReaderBufferPos + streamReaderBufferPos - preambleSize;
return pos;
}
#region Supporting methods
private static PropertyInfo _xmlReaderBufferSizeProperty;
private static long GetXmlReaderBufferLength(XmlReader xr)
{
if (_xmlReaderBufferSizeProperty == null)
{
_xmlReaderBufferSizeProperty = xr.GetType()
.GetProperty("DtdParserProxy_ParsingBufferLength",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return (int) _xmlReaderBufferSizeProperty.GetValue(xr);
}
private static PropertyInfo _xmlReaderBufferPositionProperty;
private static int GetXmlReaderBufferPosition(XmlReader xr)
{
if (_xmlReaderBufferPositionProperty == null)
{
_xmlReaderBufferPositionProperty = xr.GetType()
.GetProperty("DtdParserProxy_CurrentPosition",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return (int) _xmlReaderBufferPositionProperty.GetValue(xr);
}
private static PropertyInfo _streamReaderPreambleProperty;
private static long GetStreamReaderPreambleSize(StreamReader sr)
{
if (_streamReaderPreambleProperty == null)
{
_streamReaderPreambleProperty = sr.GetType()
.GetProperty("Preamble_Prop",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return ((byte[]) _streamReaderPreambleProperty.GetValue(sr)).Length;
}
private static PropertyInfo _streamReaderByteLenProperty;
private static long GetStreamReaderBufferLength(StreamReader sr)
{
if (_streamReaderByteLenProperty == null)
{
_streamReaderByteLenProperty = sr.GetType()
.GetProperty("ByteLen_Prop",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return (int) _streamReaderByteLenProperty.GetValue(sr);
}
private static PropertyInfo _streamReaderBufferPositionProperty;
private static int GetStreamReaderBufferPos(StreamReader sr)
{
if (_streamReaderBufferPositionProperty == null)
{
_streamReaderBufferPositionProperty = sr.GetType()
.GetProperty("CharPos_Prop",
BindingFlags.Instance | BindingFlags.NonPublic);
}
return (int) _streamReaderBufferPositionProperty.GetValue(sr);
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8637 次 |
| 最近记录: |