首页 > 解决方案 > 获取 XElement 在原始文档中的位置和长度

问题描述

我正在为特定节点解析 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 将改为扩展为四个空格。现在doc将是 108 个字符而不是 105 个字符。所以,这不是一个选择。

第二次尝试:使用 XmlReader

int GetLen(XElement el)
{
    using (var r = el.CreateReader())
    {
        r.MoveToContent();
        var ox = r.ReadOuterXml();
        return ox.Length;
    }
}

这将丢弃任何不必要的空白,导致长度更短( 86 个doc)。所以,这也不是一个选择。

除了自己手动解析 XML 之外,我还没有找到任何其他有意义的方法来完成我需要的工作,而我想避免这样做。有谁有想法,我还能尝试什么?

当然,我可以读入 xml,重新格式化它,然后使用其中一个选项。但是,由于 XML 是由外部方交付的,我们想告诉他们,我们发现错误的地方,最好知道他们的索引,而不是重新格式化后的索引。

谢谢你的帮助!

标签: c#xmlpositionlinq-to-xml

解决方案


看来,这目前是不可能的。相反,我们选择生成指向确切元素的 XPath 表达式。这样,我们可以将格式留给 UI 希望做的任何事情,但始终拥有正确的元素。


推荐阅读