1

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>

2 Answers2

2

Xnode has a feature called DeepEqual to compare nodes. XmlNode can be converted into Xnode by simple parsing.

    XElement XmlElementToXElement(XmlNode e)
    {
        return XElement.Parse(e.OuterXml);
    }

So, it will be easier from here. The method below will return true if two nodes are equal.

    bool XmlNode_DeepEquals(XmlNode node1, XmlNode node2)
    {
        XElement tempX = XmlElementToXElement(node2);
        XElement searchX = XmlElementToXElement(node1);
        return XNode.DeepEquals(tempX, searchX))
    }

This method is for comparing a list of Node.

    bool isNodeAlreadyExists(XmlNode searchNode, XmlNodeList list)
    {
        bool exists = false;
        foreach (XmlNode node in list)
        {
            if (XmlNode_DeepEquals(searchNode, node))
            {
                exists = true;
            }
        }
        return exists;
    }
  • 2
    `DeepEquals` does not take into account the order of the nodes. See [Equality Semantics of LINQ to XML Trees](https://blogs.msdn.microsoft.com/ericwhite/2009/01/27/equality-semantics-of-linq-to-xml-trees/). – Alexander Petrov May 17 '18 at 14:05
1

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");
    }
}
Stringfellow
  • 2,788
  • 2
  • 21
  • 36