/// <summary>Compares two nodes including its children and qualifier.</summary> /// <param name="leftNode">an <c>XMPNode</c></param> /// <param name="rightNode">an <c>XMPNode</c></param> /// <returns>Returns true if the nodes are equal, false otherwise.</returns> /// <exception cref="XmpException">Forwards exceptions to the calling method.</exception> private static bool ItemValuesMatch(XmpNode leftNode, XmpNode rightNode) { var leftForm = leftNode.Options; var rightForm = rightNode.Options; if (leftForm.Equals(rightForm)) { return(false); } if (leftForm.GetOptions() == 0) { // Simple nodes, check the values and xml:lang qualifiers. if (!leftNode.Value.Equals(rightNode.Value)) { return(false); } if (leftNode.Options.HasLanguage != rightNode.Options.HasLanguage) { return(false); } if (leftNode.Options.HasLanguage && !leftNode.GetQualifier(1).Value.Equals(rightNode.GetQualifier(1).Value)) { return(false); } } else { if (leftForm.IsStruct) { // Struct nodes, see if all fields match, ignoring order. if (leftNode.GetChildrenLength() != rightNode.GetChildrenLength()) { return(false); } for (var it = leftNode.IterateChildren(); it.HasNext();) { var leftField = (XmpNode)it.Next(); var rightField = XmpNodeUtils.FindChildNode(rightNode, leftField.Name, false); if (rightField == null || !ItemValuesMatch(leftField, rightField)) { return(false); } } } else { // Array nodes, see if the "leftNode" values are present in the // "rightNode", ignoring order, duplicates, // and extra values in the rightNode-> The rightNode is the // destination for AppendProperties. Debug.Assert(leftForm.IsArray); for (var il = leftNode.IterateChildren(); il.HasNext();) { var leftItem = (XmpNode)il.Next(); var match = false; for (var ir = rightNode.IterateChildren(); ir.HasNext();) { var rightItem = (XmpNode)ir.Next(); if (ItemValuesMatch(leftItem, rightItem)) { match = true; break; } } if (!match) { return(false); } } } } return(true); }