2009-07-23 30 views
6

Soy nuevo en C#, y recién comencé a usar XmlElement y su método SelectSingleNode. En mi archivo XML, hay una etiqueta que puede tener un valor (es decir, <tag>value</tag>) o estar vacía (es decir, <tag></tag>). Si está vacío, SelectSingleNode devuelve null.C# XmlElement: SelectSingleNode devuelve null para cadena vacía?

Actualmente estoy usando el siguiente código para capturar el valor de la etiqueta:

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

Este código, obviamente, plantea una excepción para las etiquetas vacías. Sin embargo, para mí, una etiqueta vacía es un valor válido, donde espero que el valor de mi cadena sea "".

Envolviendo cada llamada a SelectSingleNode con try ... catch parece una gran pérdida de código (tengo muchos campos que pueden estar vacíos), y estoy seguro de que hay una mejor manera de lograr esto.

¿Cuál es el enfoque recomendado?

EDIT:

A petición, un código XML muestra será:

<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> 

El código CS:

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

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

¿Podría publicar un ejemplo de código más completo? ¿O uno que tenga una correlación directa con un bloque de XML provisto? –

+0

¿Podría publicar un ejemplo de XML? –

+0

Sí, un poco más de muestra de código y el XML que está utilizando para analizarlo. He utilizado SelectSingleNode en el pasado y no he visto el comportamiento que mencionaste. – SolutionYogi

Respuesta

10

Su código de ejemplo:

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

es donde está el problema. La expresión XPath que has usado allí no significa "dame el texto del elemento Type". Significa "darme todos los nodos de texto hijo del elemento Tipo". Y un elemento vacío no tiene ningún nodo de texto hijo (un nodo de texto no puede estar vacío en el modelo de documento XPath). Si desea obtener el valor de texto del nodo, debe usar:

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

Ese fue el problema, gracias –

+0

Tenga en cuenta que InnerText le brinda "los valores concatenados del nodo y todos sus nodos secundarios". No recibirá el texto que espera cuando hay niños. Implementé un helper que verifica si (foundNode.NodeType == XmlNodeType.Element) {foundNode = foundNode.SelectSingleNode ("text()"); if foundNode == null {return ""; }} return foundNode.Value; –

1

El enfoque recomendado sería el uso de nueva API XML de .NET (a saber, LINQ a XML).

Aquí se muestra un ejemplo:

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 no es la "nueva API XML". Ciertamente hay razones para usar el espacio de nombres de System.Xml existente. LINQ es simplemente otro medio de usar las clases en ese espacio de nombres. –

+0

No estoy de acuerdo: System.Xml.Linq contiene una matriz de tipos nuevos para tratar con XML. Realmente es una nueva API para trabajar con XML. –

0

Tal vez esto va a funcionar para usted:

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

Eso funcionará, pero SelectSingleNode se ejecutará dos veces, incurriendo en un golpe de rendimiento innecesario. – Thorarin

+1

Bien, entonces, ¿cuál es la forma de lidiar con los elementos faltantes en el XML que dan como resultado SelectSingleNode ("// blah"). Innertext arroja una excepción? Por favor dime que no son operadores terciarios interminables ... – Fireworks

1

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

Debido a que el "valor" devuelto depende de la NodeType, existe la posibilidad de que el nodo se interpretará como un tipo que puede devolver NULL.

Usted puede ser mejor usar:

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

como XMLNode.InnerText (o XmlNode.InnerXML) devolverá una cadena, incluyendo una cadena vacía.

+1

Esto no funcionará: si SelectSingleNode devuelve nulo, no hay nada para llamar a InnerText. – Thorarin

+0

@Thorarn: Correcto. La pregunta (y el ejemplo) muestran que el nodo existe, simplemente sin texto entre las etiquetas. Recomiendo encarecidamente que compruebe si hay un nodo nulo antes de buscar un valor. –

+0

Tiene razón sobre el nodo existente ... Su explicación menciona algo sobre SelectSingleNode devolviendo nulo, pero ese no puede ser el caso si hay un elemento allí (vacío o no) – Thorarin

0

Cuando estoy realmente molesta con XML DOM, se podría escribir un método de ayuda a lo largo de las líneas de:

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

    return defaultValue; 
} 

A continuación, puede hacer lo siguiente si no está seguro existirá el nodo:

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

Si mantiene su código legible, especialmente si lo hace para varios elementos.

Dicho todo esto, SelectSingleNode (..) hace no devuelve un valor nulo si la etiqueta está vacía. El atributo Valor será nulo, sin embargo.Si usted está tratando de evitar que esto debería hacer:

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

Editar: ah, que está utilizando/texto() para seleccionar el nodo de texto real. Simplemente podría deshacerse de esa parte de XPath, pero el método NodeValue que proporcioné debería seguir funcionando (sin embargo, la parte "?? defaultValue" no es necesaria en ese caso).

+0

Esto funcionaría muy bien, ya que también se puede verificar asegúrese de que el nodo en sí mismo sea! = Nulo, sin embargo, el nodo puede existir y aún así devolver el nodo. Valor como NULO, basado en lo que es el NodeType. –

+0

@Paige: eso es ciertamente posible. Si no puede hacer esa suposición sobre su XML, debería hacer más comprobaciones. O valide contra un XSD de antemano. He actualizado el método ligeramente para no devolver nulo ahora. – Thorarin

Cuestiones relacionadas