我有一个应用程序,它接受XML文档并按某些属性对其进行排序。我有与XML文档的每一行相关的信息,我希望将其包含在已排序的文档中。为此,
当我加载文件时,我确保使用 XDocument.Load(file,LoadOptions.SetLineInfo)加载行信息。
然后我递归迭代每个XElement并获取其行信息。当我运行应用程序时,我注意到每个XElement都有两个注释,
它们包含我需要的信息,但在私人领域。
我找不到关于这些类的任何信息,我无法实例化它们,它们不会出现在 System.Xml.Linq 下的对象浏览器中。然而它们存在,我可以对它们运行“GetType()”并获取有关该类的信息。
如果它们存在,为什么它们不在MSDN引用中,为什么我不能实例化它们或扩展它们?为什么我不能在对象浏览器中找到它们?
P.S。 我的解决方法是使用反射来获取每个元素中包含的信息。但我仍然无法传递类名来告诉方法它是什么类型,我必须将对象与XElement.Annotations(typeof(object))隔离,然后在其上运行GetType()。我在下面说明了这一点。
public object GetInstanceField(Type type, object instance, string fieldName)
{
//reflective method that gets value of private field
}
XElement xEl = existingXElement; //existingXElement is passed in
var annotations = xEl.Annotations(typeof(object)); //contains two objects, start and end LineInfoAnnotation
var start = annotations.First();
var end = annotations.Last();
var startLineNumber = GetInstanceField(start.GetType(), start, lineNumber); //lineNumber is private field I'm trying to access.
var endLineNumber = GetInstanceField(end.GetType(), end, lineNumber);
这段代码有效,但我再说一遍,我不能告诉方法“typeof(LineInfoAnnotation)”,而是要在现有对象上做GetType。我无法理解这一点。
答案 0 :(得分:2)
这些类是私有的 - 如果你愿意的话,这是一个实现细节。
所有XObjects(元素,属性)都实现IXmlLineInfo接口 - 但它们显式实现了接口,因此您必须执行强制转换来访问属性。
获得IXmlLineInfo后,您可以使用属性LineNumber和LinePosition。
var data =
@"<example>
<someElement
someAttribute=""val"">
</someElement></example>
";
var doc = XDocument.Load(new MemoryStream(Encoding.UTF8.GetBytes(data)), LoadOptions.SetLineInfo);
foreach(var element in doc.Descendants()) {
var elLineInfo = element as IXmlLineInfo;
Console.Out.WriteLine(
$"Element '{element.Name}' at {elLineInfo.LineNumber}:{elLineInfo.LinePosition}");
foreach(var attr in element.Attributes()) {
var attrLineInfo = attr as IXmlLineInfo;
Console.Out.WriteLine(
$"Attribute '{attr.Name}' at {attrLineInfo.LineNumber}:{attrLineInfo.LinePosition}");
}
}
输出:
Element 'example' at 1:2
Element 'someElement' at 2:2
Attribute 'someAttribute' at 3:3
要获取EndElement信息,您必须使用普通的旧XML阅读器,因为XObject api不会公开有关元素结束位置的任何信息。
using(var reader = doc.CreateReader()) {
while(reader.Read()) {
var lineInfo = reader as IXmlLineInfo;
Console.Out.WriteLine($"{reader.NodeType} {reader.Name} at {lineInfo.LineNumber}:{lineInfo.LinePosition}");
if(reader.NodeType == XmlNodeType.Element && reader.HasAttributes) {
while(reader.MoveToNextAttribute()) {
Console.Out.WriteLine($"{reader.NodeType} {reader.Name} at {lineInfo.LineNumber}:{lineInfo.LinePosition}");
}
}
}
}
输出:
Element example at 1:2
Element someElement at 2:2
Attribute someAttribute at 3:3
EndElement someElement at 5:5
EndElement example at 5:19