2009-06-22 18 views
24

¿Alguien sabe cómo puedo verificar si una cadena contiene XML bien formado sin usar algo como XmlDocument.LoadXml() en un bloque try/catch? Recibí comentarios que pueden ser XML o no, y quiero un código que reconozca que la entrada puede no ser XML sin depender de un try/catch, tanto para la velocidad como sobre el principio general de que circunstancias no excepcionales no deberían aumentar excepciones Actualmente tengo un código que hace esto;¿Comprueba el XML bien formado sin try/catch?

private bool IsValidXML(string value) 
    { 
     try 
     { 
      // Check we actually have a value 
      if (string.IsNullOrEmpty(value) == false) 
      { 
       // Try to load the value into a document 
       XmlDocument xmlDoc = new XmlDocument(); 

       xmlDoc.LoadXml(value); 

       // If we managed with no exception then this is valid XML! 
       return true; 
      } 
      else 
      { 
       // A blank value is not valid xml 
       return false; 
      } 
     } 
     catch (System.Xml.XmlException) 
     { 
      return false; 
     } 
    } 

Pero parece algo que no debería requerir la prueba/captura. La excepción está causando un infierno durante la depuración porque cada vez que verifico una cadena, el depurador se romperá aquí, 'ayudándome' con mi molesto problema.

+0

Si el depurador es su problema que sólo puede apagar el manejo del usuario XmlExceptions. Use el acceso directo en VS: Ctrl + Alt + E, busque System.Xml.XmlException y desactívelo. – nashwan

Respuesta

21

no sé una manera de validar sin excepción, pero se puede cambiar la configuración del depurador a romper solamente para XmlException si es no controlada - que debe resolver sus problemas inmediatos, incluso si el código es todavía poco elegante.

Para ello, vaya a depurar/Excepciones Excepciones .../Common Language Runtime y encontrar System.Xml.XmlException, a continuación, asegúrese de que sólo "el usuario no controlada" está marcada (sin torcer).

+0

+1 para esta solución de salvamento. Solo habilito la excepción de inicio de sesión si tengo que depurar el código que falla. – OregonGhost

5

Esa es una forma razonable de hacerlo, excepto que IsNullOrEmpty es redundante (LoadXml puede resolverlo bien). Si mantiene IsNullOrEmpty, haga if (! String.IsNullOrEmpty (value)).

Básicamente, sin embargo, su problema es el depurador, no el código.

+0

He llegado a un acuerdo. Marqué el método con un atributo de depuración [DebuggerStepThrough] que detiene el depurador que se detiene en la excepción. –

+0

IsNullOrEmpty es solo una optimización para evitar la sobrecarga de una excepción cuando se llama a IsValidXml (""), lo que sucede mucho en mi programa. –

3

Agregue el atributo [System.Diagnostics.DebuggerStepThrough] al método IsValidXml. Esto suprime que XmlException sea capturado por el depurador, lo que significa que puede activar la captura de excepciones de primer cambio y este método en particular no será depurado.

1

La clase XmlTextReader es un implementación de XmlReader y proporciona un analizador performant rápido. Es aplica las reglas que XML debe ser bien formado. No es un validador ni un analizador no validador ya que no tiene información de DTD o esquema . Puede leer texto en bloques , o leer caracteres de una secuencia .

Y un ejemplo de otro artículo de MSDN a la que he añadido código para leer todo el contenido de la secuencia XML.

string str = "<ROOT>AQID</ROOT>"; 
XmlTextReader r = new XmlTextReader(new StringReader(str)); 
try 
{ 
    while (r.Read()) 
    { 
    } 
} 
finally 
{ 
    r.Close(); 
} 

fuente: http://bytes.com/topic/c-sharp/answers/261090-check-wellformedness-xml

0

no estoy de acuerdo en que el problema es el depurador. En general, para casos no excepcionales, se deben evitar excepciones. Esto significa que si alguien está buscando un método como IsWellFormed() que devuelva verdadero/falso en función de si la entrada está bien formada XML o no, las excepciones no deben arrojarse dentro de esta implementación, independientemente de si son capturadas y manejadas o no.

Las excepciones son costosas y no se deben encontrar durante una ejecución exitosa normal. Un ejemplo es escribir un método que comprueba la existencia de un archivo y usar File.Open y capturar la excepción en el caso de que el archivo no exista. Esta sería una implementación pobre.En su lugar, se debe usar File.Exists() (y es de esperar que la implementación de eso no se limite a probar/capturar algún método que arroje una excepción si el archivo no existe, estoy seguro de que no).

+0

No estoy seguro de que esta respuesta sea útil. No ha suministrado una forma alternativa de verificar una buena formación que no genere una excepción. Parece una afirmación sobre tus pensamientos sobre los métodos que arrojan excepciones. –

+0

Steve explícitamente pide una forma de hacer esto sin try-catch, por lo que decirle que debería hacerlo sin try-catch realmente no es útil y raya en el sarcasmo. –

+0

No estaba tratando de ser sarcástico y sé que no estaba respondiendo la pregunta. Pensé que eso era obvio. Estaba comentando sobre otros comentarios. Creo que debería haber agregado mi respuesta como un comentario a la respuesta que estaba comentando. – nickdu

5

Steve,

Tuvimos una tercera parte que accidentalmente veces nos envió JSON en lugar de XML. Esto es lo que implementé:

public static bool IsValidXml(string xmlString) 
{ 
    Regex tagsWithData = new Regex("<\\w+>[^<]+</\\w+>"); 

    //Light checking 
    if (string.IsNullOrEmpty(xmlString) || tagsWithData.IsMatch(xmlString) == false) 
    { 
     return false; 
    } 

    try 
    { 
     XmlDocument xmlDocument = new XmlDocument(); 
     xmlDocument.LoadXml(xmlString); 
     return true; 
    } 
    catch (Exception e1) 
    { 
     return false; 
    } 
} 

[TestMethod()] 
public void TestValidXml() 
{ 
    string xml = "<result>true</result>"; 
    Assert.IsTrue(Utility.IsValidXml(xml)); 
} 

[TestMethod()] 
public void TestIsNotValidXml() 
{ 
    string json = "{ \"result\": \"true\" }"; 
    Assert.IsFalse(Utility.IsValidXml(json)); 
} 
0

Sólo mi 2 centavos - hay varias preguntas sobre este torno, y la mayoría de las personas están de acuerdo en la "basura - sale basura" hecho. No estoy en desacuerdo con eso, pero personalmente encontré la siguiente solución rápida y sucia, especialmente para los casos en los que trata con datos xml de terceros que simplemente no se comunican fácilmente con usted. No evita usar try/catch - pero lo usa con una granularidad más fina, así que en los casos donde la cantidad de caracteres xml no válidos no es tan grande, ayuda ... Usé XmlTextReader, y su método ReadChars() para cada elemento padre, que es uno de los comandos que no hacen comprobaciones bien formadas, como lo hace ReadInner/OuterXml. Por lo tanto, es una combinación de Read() y ReadChars() cuando Read() se repite en un nodo primario. Por supuesto, esto funciona porque puedo suponer que la estructura básica del XML está bien, pero los contenidos (valores) de ciertos nodos pueden contener caracteres especiales que no han sido reemplazados por & ...; equivalente ... (He encontrado un artículo acerca de esto en alguna parte, pero no puedo encontrar el enlace de la fuente en el momento)

-1

Mis dos centavos. Esto era bastante simple y sigue algunas convenciones comunes ya que se trata de análisis ...

public bool TryParse(string s, ref XmlDocument result) 
{ 
    try { 
     result = new XmlDocument(); 
     result.LoadXml(s); 
     return true; 
    } catch (XmlException ex) { 
     return false; 
    } 
} 
1

Precaución con el uso de XmlDocument posible cargar un elemento en la línea de <0>some text</0> usando XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(object)sin una excepción de ser lanzado.

Los nombres de elementos numéricos no son válidos xml, y en mi caso no ocurrió un error hasta que traté de escribir el xmlDoc.innerText a un tipo de datos de servidor Sql de xml.

Esto cómo puedo validar ahora, y una excepción es lanzada
XmlDocument tempDoc = XmlDocument)JsonConvert.DeserializeXmlNode(formData.ToString(), "data"); doc.LoadXml(tempDoc.InnerXml);

+0

Buen punto: el estándar xml dice 'este seguido de cero o más caracteres de nombre - [4] NameChar :: = Letter | Digit | ''. | '-' | '_' | ':' | CombiningChar | Extender [5] Nombre :: = (Letra | '_' | ':') (NameChar) * –

Cuestiones relacionadas