Object position (line, column) in XML after deserialization .NET

前端 未结 2 604
我寻月下人不归
我寻月下人不归 2020-12-17 02:54

How can I get position in the original xml file of an xml tag after deserialization into a .NET object using XmlSerializer ?

Here is an example XML

          


        
2条回答
  •  余生分开走
    2020-12-17 03:16

    I tried several approaches. Two of them:

    • Implement IXmlSerializable. In principle this would work, but then one would have to implement the complete deserialization mechanism.

    • Deserialize using an XmlReader, save a reference to that XmlReader at some static location, and in the constructor of classes that are deserialized, access that XmlReader and retrieve line and position information. Cons: static; relatively complicated.

    I did not find a way to get more information than start line and position, but honestly, that’s enough for my use case.

    Currently I think I will use the following approach.

    • Load the XML file with line information:

      XDocument xdoc = XDocument.Parse(xml, LoadOptions.SetLineInfo);
      
    • To all elements in xdoc, add a new attribute (e.g. NewId) that allows to identify the elements, e.g. give the first element a 0, the second a 1, etc.

    • Make sure all classes that are deserialized (in your case AddressDetails) will have such a NewId, e.g.:

          [XmlAttribute]
          public int NewId { get; set; }
      

      This can be done by deriving from a common base class, and even when xsd.exe is used to create the classes, this is possible because it will create all classes as partial (e.g. a partial class foo : MyBaseClassElement { } needs to be added somewhere for all classes).

    • After deserializing, for each element that has been deserialized as a class object, the XElement from which it has been deserialized can be looked up using NewId. (To speed up the look up, one can use a List that contains all XElement such that NewId is the index in that list.)

    • Casting the XElement to IXmlLineInfo will give line and position information.

    • For elements that have not been deserialized as a class object (e.g. Number in your example) and for attributes, first look up the XElement that contains a NewId (e.g. AdressDetails), then query the element’s or attribute’s line information:

      XElement element = ...;
      XNode descendant = element.Descendants(childElementOrAttributetName).FirstOrDefault();
      return descendant as IXmlLineInfo;
      

    Cons:

    • Memory usage.
    • Need to add attribute to all classes.

提交回复
热议问题