Search code examples
c#xmlxmlnodedeepequals

How to compare two XmlNodes of XmlDocument in C#?


This is a sample xml. If a new font is to be added in the sense, all the existing fonts to be compare with the new font before adding to the preference. How do I check the node(font) whether already exists or not in case of XmlDocument?

<preferences>
  <font role="console">
    <size>9</size>
    <fname>Courier</fname>
  </font>
  <font role="default">
    <fname>Times New Roman</fname>
    <size>14</size>
  </font>
  <font role="titles">
    <size>10</size>
    <fname>Helvetica</fname>
  </font>
</preferences>

Solution

  • One approach would be to create a couple of classes to represent the XML document and implement the IEquatable<T> Interface.

    https://dotnetfiddle.net/QZFwDy

    Classes for XML

    [XmlRoot(ElementName = "font")]
    public class Font : IEquatable<Font>
    {
        [XmlElement(ElementName = "size")]
        public string Size { get; set; }
        [XmlElement(ElementName = "fname")]
        public string Fname { get; set; }
        [XmlAttribute(AttributeName = "role")]
        public string Role { get; set; }
    
        public bool Equals(Font font)
        {
            if (font == null) return false;
    
            return (Size == font.Size) && (Fname == font.Fname) && (Role == font.Role);
        }
    }
    
    [XmlRoot(ElementName = "preferences")]
    public class Preferences
    {
        [XmlElement(ElementName = "font")]
        public List<Font> Font { get; set; }
    }
    

    Then use the Preferences class to deserialize the XML. Once the document is deserialized, leverage the List<T>.Contains(T item) method to see if the font node exists. The .Contains method will call the implementation of Equals in the Font class.

    Code to Demonstrate

    static void Main(string[] args)
    {
        Preferences preferences = null;
        var xmlString = Data.XML;
    
        using (var stream = new StringReader(xmlString))
        {
            var serializer = new XmlSerializer(typeof(Preferences));
            preferences = (Preferences)serializer.Deserialize(stream);
        }
    
        var node0 = new Font()
        {
            Fname = "New One",
            Role = "console",
            Size = "12"
        };
    
        var node1 = new Font()
        {
            Fname = "Helvetica",
            Role = "titles",
            Size = "10"
        };
    
        if (preferences.Font.Contains(node0))
        {
            // Not expecting to enter here
            Console.WriteLine($"'{nameof(node0)}' is already present");
        }
    
        if (preferences.Font.Contains(node1))
        {
            Console.WriteLine($"'{nameof(node1)}' is already present");
        }
    }