获取 XElement 在原始文档中的位置和长度
Get an XElement's position and length in the original document
我正在为特定节点解析 XML 文档,稍后想在 ui 中显示 xml 文档,突出显示特定部分。为此,我需要知道元素在文档文本中的位置及其长度。
到目前为止,我发现,在加载XDocument时,我应该指定LoadOptions.SetLineInfo
,这样我至少可以得到原始xml字符串中的位置。这为我提供了元素名称开始的字符,因此我应该减去一个,以获得标签的实际开始。但是,我无法找到获取结束元素位置的方法。
到目前为止我已经尝试过(LinqPad代码使用.Dump()
,必要时替换为Console.WriteLine
),基本测试代码:
var xml = @"<xml>
<myElement>
<someProperty attribu=""attrVal1"" />
<someOtherProp />
</myElement>
</xml>";
// xml.Length => 105 (Note, there should be a TAB instead of four spaces before `<someOtherProp />`,
// to demonstrate problems)
var doc = XDocument.Parse(xml, LoadOptions.SetLineInfo);
var li = (IXmlLineInfo)doc;
$"{li.LineNumber - 1}:{li.LinePosition - 1}~{GetLen(doc.Root)}".Dump();
foreach (var el in doc.XPathSelectElements("//myElement/*"))
{
li = (IXmlLineInfo) el;
$"{li.LineNumber - 1}:{li.LinePosition - 1}~{GetLen(el)}".Dump();
}
现在,我的 GetLen
实现:
第一次尝试:使用.ToString()
int GetLen(XElement el)
{
return el.ToString().Length;
}
这将重新格式化代码,因此上面注释中提到的 TAB 将扩展为四个 space。 doc
将是 108 个字符,而不是现在的 105 个。所以,这不是一个选择。
第二次尝试:使用 XmlReader
int GetLen(XElement el)
{
using (var r = el.CreateReader())
{
r.MoveToContent();
var ox = r.ReadOuterXml();
return ox.Length;
}
}
这将丢弃任何不必要的白色 space,导致长度更短(doc
为 86)。所以,这也不是一个选择。
除了我自己手动解析 XML 之外,我还没有找到任何其他有意义的方法来完成我的需要,我想避免这样做。有没有人有想法,我还能尝试什么?
当然,我可以阅读 xml,重新格式化,然后使用其中一个选项。但是,由于XML是外送的,我们要告诉他们,我们发现错误的地方,最好知道他们的索引,而不是重新格式化后的索引。
感谢您的帮助!
目前看来,这是不可能的。相反,我们选择生成一个指向确切元素的 XPath 表达式。这样,我们可以将格式保留为 UI 想要的任何格式,但始终具有正确的元素。
我正在为特定节点解析 XML 文档,稍后想在 ui 中显示 xml 文档,突出显示特定部分。为此,我需要知道元素在文档文本中的位置及其长度。
到目前为止,我发现,在加载XDocument时,我应该指定LoadOptions.SetLineInfo
,这样我至少可以得到原始xml字符串中的位置。这为我提供了元素名称开始的字符,因此我应该减去一个,以获得标签的实际开始。但是,我无法找到获取结束元素位置的方法。
到目前为止我已经尝试过(LinqPad代码使用.Dump()
,必要时替换为Console.WriteLine
),基本测试代码:
var xml = @"<xml>
<myElement>
<someProperty attribu=""attrVal1"" />
<someOtherProp />
</myElement>
</xml>";
// xml.Length => 105 (Note, there should be a TAB instead of four spaces before `<someOtherProp />`,
// to demonstrate problems)
var doc = XDocument.Parse(xml, LoadOptions.SetLineInfo);
var li = (IXmlLineInfo)doc;
$"{li.LineNumber - 1}:{li.LinePosition - 1}~{GetLen(doc.Root)}".Dump();
foreach (var el in doc.XPathSelectElements("//myElement/*"))
{
li = (IXmlLineInfo) el;
$"{li.LineNumber - 1}:{li.LinePosition - 1}~{GetLen(el)}".Dump();
}
现在,我的 GetLen
实现:
第一次尝试:使用.ToString()
int GetLen(XElement el)
{
return el.ToString().Length;
}
这将重新格式化代码,因此上面注释中提到的 TAB 将扩展为四个 space。 doc
将是 108 个字符,而不是现在的 105 个。所以,这不是一个选择。
第二次尝试:使用 XmlReader
int GetLen(XElement el)
{
using (var r = el.CreateReader())
{
r.MoveToContent();
var ox = r.ReadOuterXml();
return ox.Length;
}
}
这将丢弃任何不必要的白色 space,导致长度更短(doc
为 86)。所以,这也不是一个选择。
除了我自己手动解析 XML 之外,我还没有找到任何其他有意义的方法来完成我的需要,我想避免这样做。有没有人有想法,我还能尝试什么?
当然,我可以阅读 xml,重新格式化,然后使用其中一个选项。但是,由于XML是外送的,我们要告诉他们,我们发现错误的地方,最好知道他们的索引,而不是重新格式化后的索引。
感谢您的帮助!
目前看来,这是不可能的。相反,我们选择生成一个指向确切元素的 XPath 表达式。这样,我们可以将格式保留为 UI 想要的任何格式,但始终具有正确的元素。