如何将XmlReader返回的行号和行位置转换为XML字符串索引?
解决XmlReader解析分段XML时截取未完成部分的问题
核心思路
要将IXmlLineInfo获取的行号、位置转换为原始XML字符串的索引,本质是统计原始字符串中目标行之前所有行的总字符数,再加上当前行的位置偏移量。
具体实现步骤
- 预处理原始XML:提前遍历原始XML字符串,记录每一行起始字符在字符串中的索引,存入列表
lineStartIndices(列表索引从0开始,对应第1行及以后的行起始位置)。- 遍历过程中需兼容
\n、\r\n、\r三种换行格式,确保每行起始位置记录准确。
- 遍历过程中需兼容
- 计算目标索引:
- 若行号为1,直接用
linePosition - 1(因为LinePosition从1开始计数,转成0-based索引需减1)。 - 若行号大于1,取
lineStartIndices[lineNumber - 2](对应目标行的上一行起始索引),再加上linePosition - 1,得到最终的字符串索引。
- 若行号为1,直接用
- 截取未完成部分:用
Substring(目标索引)从原始XML中截取未完成的片段,后续与新接收的数据包拼接即可。
代码示例
// 预处理XML,生成每行起始索引的列表 List<int> GetLineStartIndices(string xml) { var lineStarts = new List<int> { 0 }; // 第一行起始索引为0 int index = 0; while (index < xml.Length) { if (xml[index] == '\r') { // 处理Windows换行符\r\n if (index + 1 < xml.Length && xml[index + 1] == '\n') { lineStarts.Add(index + 2); index += 2; } else { lineStarts.Add(index + 1); index++; } } else if (xml[index] == '\n') { // 处理Unix换行符\n lineStarts.Add(index + 1); index++; } else { index++; } } return lineStarts; } // 将行号和位置转换为原始字符串的索引 int ConvertLineInfoToIndex(string xml, int lineNumber, int linePosition) { var lineStarts = GetLineStartIndices(xml); if (lineNumber == 1) { return linePosition - 1; } if (lineNumber > lineStarts.Count) { throw new ArgumentOutOfRangeException(nameof(lineNumber)); } int lineStartIndex = lineStarts[lineNumber - 2]; return lineStartIndex + linePosition - 1; }
注意事项
- 若原始XML包含BOM(字节顺序标记),需先移除BOM再处理,否则会导致起始索引计算偏差。
- 确保
IXmlLineInfo的有效性:并非所有XmlReader实现都支持IXmlLineInfo,使用前需先通过reader is IXmlLineInfo判断。
内容的提问来源于stack exchange,提问作者Étienne Laneville
相关产品推荐
相关产品推荐

