2015-01-08 4 views
6

mi sprawdzenie, czy dwa elementy XML podane przez struny są równe z tą metodą:Sprawdź, czy element XML równa kolejny element XML, ignorując pustych wartości

private static bool XmlEquals(string s1, string s2) 
{ 
    return XNode.DeepEquals(XElement.Parse(s1), XElement.Parse(s2)); 
} 

Ta praca chyba jednym z elementów jest otwieranie i zamykanie znaczniki, a druga ma zamkniętą tag tak:

<MyElement SomeAttribute="some value" /> 
<MyElement SomeAttribute="some value"></MyElement> 

można jakoś porównać dwa elementy XML w taki sposób, że powyższy przypadek jest rozpatrywany równe?

+0

Czy spróbować porównać je jako ciąg? –

+0

Myślę, że trzeba poszukać implementacji drzewa niż przechodzić przez sprawdzanie węzłów: http://msdn.microsoft.com/en-us/library/bb348073%28v=vs.110%29.aspx – LordTitiKaka

+4

To pytanie wydaje się mieć podobne, jeśli nie równe, różnice semantyczne: http://stackoverflow.com/questions/7318157/best-way-to-compare-xelement-objects –

Odpowiedz

2

prosty sposób rozwiązać ten konkretny problem polega na introduce closing brackets explicitly:

private static bool XmlEquals(string s1, string s2) 
{ 
     var firstElement = XElement.Parse(s1); 
     var secondElement = XElement.Parse(s2); 
     IntroduceClosingBracket(firstElement); 
     IntroduceClosingBracket(secondElement); 

     return XNode.DeepEquals(firstElement, secondElement); 
} 

private static void IntroduceClosingBracket(XElement element) 
{ 
     foreach (var descendant in element.DescendantsAndSelf()) 
     { 
      if (descendant.IsEmpty) 
      { 
       descendant.SetValue(String.Empty); 
      } 
     } 
} 

pętli wszystkich potomków może spowodować spadek wydajności, chociaż.

+0

To jest najlepsze rozwiązanie, jakie widziałem do tej pory, działa, ale musiałem dodać 'if (element.IsEmpty) {element.SetValue (string.Empty); } 'w metodzie' IntroduceClosingBracket', aby działał poprawnie. – Hinek

+0

@Hinek Och, głuptasie, napisałem test od zagnieżdżonych elementów od początku i nie sprawdziłem oczywistego przypadku. Naprawię to, dziękuję! –

+0

Teraz jest pięknie. Dzięki, byłaś wielką pomocą! – Hinek

-5

Zawsze można podzielić struny na cudzysłów, a następnie porównać je.

s1Array = s1.Split('\"'); 
s2Array = s2.Split('\"'); 

if(s1[0] == s2[0] && s1[1] == s2[1]) 
    return true; 

Ignorując pustych wartości jest tak proste, jak sprawdzanie

if(s1[1] == String.Empty || s1[1] == null)... 
+6

Jak dokładnie to pomaga? Działa to tylko w skrajnie ograniczonej liczbie okoliczności. –

1

Jeśli XML nie musi być dokładnie taki sam jak w rozwiązaniu @ defaultlocale, które naprawdę porównuje wszystko (nawet komentarze), można użyć LINQ, aby porównać tylko te rzeczy, które są zainteresowane. Aby pokazać pomysł zrobiłem porównanie wartości atrybutów opcjonalne. Dane

Test:

var xml1 = @" 
    <elm1 attr1='val1'> 
     <elm2 attr2='val1'> 
      <elm3 attr3='val1' /> 
     </elm2> 
    </elm1>"; 

var xml2 = @" 
    <elm1 attr1='val1'> 
     <elm2 attr2='val1'> 
      <elm3 attr3='val1' attr='val2' /> 
     </elm2> 
    </elm1>"; 

rekurencyjne porównanie:

// Just a helper. 
private static Tuple<XElement, XElement> Compare(
    string xml1, 
    string xml2, 
    bool compareAttributeValues) 
{ 
    return Compare(
     XElement.Parse(xml1), 
     XElement.Parse(xml2), 
     compareAttributeValues); 
} 

// Compares XElements recursively 
// and returns the two nodes that are different if any. 
private static Tuple<XElement, XElement> Compare(
    XElement xElm1, 
    XElement xElm2, 
    bool compareAttributeValues) 
{ 
    // Elements are different if they have a different number of children. 
    if (xElm1.Elements().Count() != xElm2.Elements().Count()) 
    { 
     return new Tuple<XElement, XElement>(xElm1, xElm2); 
    } 

    // Enumerate both elements at the same time. 
    var elements = Enumerable.Zip(
     xElm1.Elements(), 
     xElm2.Elements(), 
     (x, y) => new Tuple<XElement, XElement>(x, y)); 
    foreach (var item elements) 
    { 
     // Elements are equal if they have the same names... 
     bool haveSameNames = xElm1.Name.LocalName == xElm2.Name.LocalName; 

     // and the same attributes. 
     bool haveSameAttributes = 
      item.Item1 
      // Concatenate and group attributes by their name. 
      .Attributes() 
      .Concat(item.Item2.Attributes()) 
      .GroupBy(x => x.Name.LocalName, (key, items) => new 
      { 
       Name = key, 
       Items = items, 
       // Attiribute value comparison can be skipped. 
       // If enabled compare attribute values. 
       // They are equal if the result is only one group. 
       HaveSameValues = 
        compareAttributeValues == false 
        || items.GroupBy(y => y.Value).Count() == 1, 
       Count = items.Count() 
      }) 
      // Each attribute group must contain two items 
      // if they are identical (one per element). 
      .Where(x => x.Count != 2 || x.HaveSameValues == false) 
      .Any() == false; 
     if (!haveSameNames || !haveSameAttributes) 
     { 
      return item; 
     } 
     else 
     { 
      // Return the different nodes. 
      return Compare(item.Item1, item.Item2, compareAttributeValues); 
     } 
    } 
    // No differences found. 
    return null; 
} 
+1

Co, jeśli czasami moje elementy mają podelementy? – Hinek

+0

Możesz wywoływać to w metodzie rekursywnej i porównywać ze sobą każdy element, a następnie zagłębiać się, jeśli elementy są równe, dopóki nie znajdziesz różnicy. – t3chb0t

+0

Twój przykład był bardzo prosty i polegał na porównaniu tylko dwóch elementów. Nie powiedziałeś nic o drzewach ani rekursji. – t3chb0t

Powiązane problemy