2009-07-23 18 views
6

Jestem nowy w języku C# i właśnie zacząłem używać XmlElement i jego metody SelectSingleNode. W moim pliku XML znajduje się tag, który może mieć wartość (tj. <tag>value</tag>) lub być pusty (tj. <tag></tag>). Jeśli jest pusty, SelectSingleNode zwraca wartość null.C# XmlElement: SelectSingleNode zwraca wartość pustą dla pustego ciągu?

obecnie używam następujący kod do połowu wartość tagu:

XmlElement elem = .... 
string s = elem.SelectSingleNode("somepath").Value; 

Ten kod oczywiście podnosi wyjątek dla pustych tagów. Jednak dla mnie pusty tag jest prawidłową wartością, gdzie oczekuję wartości "" mojego ciągu.

Zawijanie każdego połączenia do SelectSingleNode z try ... catch wydaje się ogromnym marnowaniem kodu (mam wiele pól, które mogą być puste) i jestem pewien, że jest lepszy sposób na osiągnięcie tego.

Jakie jest zalecane podejście?

EDIT:

następstwie wniosków, przykładowy kod XML będzie:

<Elements> 
    <Element> 
     <Name>Value</Name> 
     <Type>Value</Type> <-- may be empty 
     <Color>Value</Color> 
    </Element> 
    <Element> 
     <Name>Value</Name> 
     <Type>Value</Type> 
     <Color>Value</Color> 
    </Element> 
</Elements> 

Kod CS:

XmlDocument doc = new XmlDocument(); 
doc.Load("name.xml"); 

foreach (XmlElement elem in doc.SelectNodes("Elements/Element")) 
{ 
    myvalue = elem.SelectSingleNode("Type/text()").Value; 
} 
+3

Czy możesz zamieścić bardziej kompletny przykład kodu? Lub taki, który ma bezpośrednią korelację z dostarczonym blokiem XML? –

+0

Czy możesz opublikować próbkę XML? –

+0

Tak, trochę więcej przykładowego kodu i XML, którego używasz do parsowania. Użyłem SelectSingleNode w przeszłości i nie widziałem takiego zachowania, o którym wspomniałeś. – SolutionYogi

Odpowiedz

10

Twój przykładowy kod:

myvalue = elem.SelectSingleNode("Type/text()").Value; 

gdzie jest problem. Wyrażenie XPath, którego tam użyłeś, nie oznacza "daj mi tekstu elementu Type". Oznacza to "daj mi wszystkie węzły tekstu podrzędnego typu elementu". I pusty element nie ma żadnych podrzędnych węzłów tekstowych (węzeł tekstowy nie może być pusty w modelu dokumentu XPath). Jeśli chcesz uzyskać wartość tekstową węzła, powinieneś użyć:

myvalue = elem.SelectSingleNode("Type").InnerText; 
+0

To był problem, dziękuję –

+0

Należy zauważyć, że InnerText daje "połączone wartości węzła i wszystkich jego węzłów podrzędnych." Nie dostaniesz tekstu, którego oczekujesz, gdy są dzieci. Zaimplementowałem helpera, który sprawdza, czy (foundNode.NodeType == XmlNodeType.Element) {foundNode = foundNode.SelectSingleNode ("text()"); jeśli foundNode == null {return ""; }} return foundNode.Value; –

1

Zalecane podejście byłoby użyć .NET nowego XML API (a mianowicie LINQ do XML).

Oto przykład:

using System; 
using System.Linq; 
using System.Xml.Linq; 

class Program 
{ 
    static void Main() 
    { 
     String xml = @"<Root><Value></Value></Root>"; 

     var elements = XDocument.Parse(xml) 
      .Descendants("Value") 
      .Select(e => e.Value); 
    } 
} 
+0

LINQ to XML nie jest "nowym interfejsem API XML". Z pewnością istnieją powody do używania istniejącej przestrzeni nazw System.Xml. LINQ to po prostu kolejny sposób korzystania z klas w tej przestrzeni nazw. –

+0

Nie zgadzam się - System.Xml.Linq zawiera tablicę nowych typów do obsługi XML. To naprawdę nowy interfejs API do pracy z XML. –

0

Może to będzie pracować dla Ciebie:

string s = elem.SelectSingleNode("somepath") != null ? elem.SelectSingleNode("somepath").value : "" 
+0

To zadziała, ale SelectSingleNode zostanie wykonane dwukrotnie, powodując niepotrzebne trafienie wydajności. – Thorarin

+1

Okay, więc w jaki sposób radzić sobie z brakującymi elementami w XML, które powodują SelectSingleNode ("// blah"). Innertext rzuca wyjątek? Proszę mi powiedzieć, że to nie są nieskończone trzeciorzędne operatory ... – Fireworks

1

http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.value(VS.71).aspx

Ponieważ "wartość" zwróciło zależy od wartości NodeType, istnieje szansa że węzeł zostanie zinterpretowany jako typ, który może zwrócić wartość NULL.

może być lepiej wyłączyć za pomocą:

XmlElement elem = .... 
string s = elem.SelectSingleNode("somepath").InnerText; 

jak XMLNode.InnerText (lub XmlNode.InnerXML) zwróci łańcuch, łącznie z łańcuchem pustym.

+1

To nie zadziała: jeśli SelectSingleNode zwróci wartość null, nie ma nic do wywołania InnerText. – Thorarin

+0

@ Thorarn: Prawidłowe. Pytanie (i przykład) pokazują, że węzeł istnieje, tylko bez tekstu między tagami. Gorąco polecam sprawdzenie węzła zerowego przed sprawdzeniem wartości. –

+0

Masz rację co do istniejącego węzła ... Jego wyjaśnienie wspomniało coś o zwracaniu null SelectSingleNode, ale nie może być tak, jeśli jest tam element (pusty lub nie) – Thorarin

0

Kiedy jestem naprawdę przeszkadza z XML DOM, można napisać metodę pomocnika wzdłuż linii:

static string NodeValue(XmlNode node, string defaultValue) 
{ 
    if (node != null) 
     return node.Value ?? defaultValue; 

    return defaultValue; 
} 

Następnie można wykonać następujące czynności, jeśli nie jesteś pewien węzeł będzie istniał:

string s = NodeValue(elem.SelectSingleNode("Type"), String.Empty); 

Zachowuje czytelność kodu, zwłaszcza jeśli robisz to dla wielu elementów.

Wszystko, co jest powiedziane, SelectSingleNode (..) robi nie zwraca wartość pustą, jeśli znacznik jest pusty. Atrybut Wartość będzie jednak pusty.Jeśli jesteś po prostu staramy się obejść, że powinien to zrobić:

string s = elem.SelectSingleNode("Type").Value ?? String.Empty; 

EDIT: ah, używasz/text(), aby wybrać rzeczywistej węzeł tekstowy. Możesz po prostu pozbyć się tej części XPath, ale dostarczona przeze mnie metoda NodeValue powinna nadal działać (w tym przypadku część "?? defaultValue" nie jest potrzebna).

+0

To by działało ładnie, ponieważ również sprawdza upewnij się, że sam węzeł jest! = Null, jednak węzeł może istnieć i nadal zwracać node.Value jako NULL, w zależności od tego, czym jest NodeType. –

+0

@Paige: to na pewno możliwe. Jeśli nie możesz sformułować tego założenia na temat XML, powinieneś zrobić więcej kontroli. Lub wcześniej sprawdź na XSD. Zaktualizowałem nieco metodę, aby nie zwracać teraz wartości null. – Thorarin

Powiązane problemy