2009-09-29 15 views
12

Tenemos un campo de cadena que puede contener XML o texto sin formato. El XML no contiene ningún encabezado <?xml, y ningún elemento raíz, es decir, no está bien formado.¿Cómo saber si una cadena es xml?

Necesitamos ser capaces de redactar datos XML, elementos de vaciado y valores de atributo, dejando solo sus nombres, así que tengo que probar si esta cadena es XML antes de que se redacte.

Actualmente estoy usando este enfoque:

string redact(string eventDetail) 
{ 
    string detail = eventDetail.Trim(); 
    if (!detail.StartsWith("<") && !detail.EndsWith(">")) return eventDetail; 
    ... 

¿Hay una mejor manera?

¿Hay algún caso extremo que este enfoque podría perderse?

Aprecio que podría usar XmlDocument.LoadXml y atrapar XmlException, pero esto parece una opción costosa, ya que sé que muchos de los datos no estarán en XML.

He aquí un ejemplo de los datos XML, además de la falta de un elemento raíz (que se omite para ahorrar espacio, ya que habrá una gran cantidad de datos), podemos suponer que está bien formado:

<TableName FirstField="Foo" SecondField="Bar" /> 
<TableName FirstField="Foo" SecondField="Bar" /> 
... 

Actualmente, solo utilizamos valores basados ​​en atributos, pero podemos usar elementos en el futuro si los datos se vuelven más complejos.

SOLUCIÓN

Sobre la base de varios comentarios (gracias chicos!)

string redact(string eventDetail) 
{ 
    if (string.IsNullOrEmpty(eventDetail)) return eventDetail; //+1 for unit tests :) 
    string detail = eventDetail.Trim(); 
    if (!detail.StartsWith("<") && !detail.EndsWith(">")) return eventDetail; 
    XmlDocument xml = new XmlDocument(); 
    try 
    { 
     xml.LoadXml(string.Format("<Root>{0}</Root>", detail)); 
    } 
    catch (XmlException e) 
    { 
     log.WarnFormat("Data NOT redacted. Caught {0} loading eventDetail {1}", e.Message, eventDetail); 
     return eventDetail; 
    } 
    ... // redact 
+0

Me gustaría ir con el LoadXml, de esa manera usted sabe que los datos "XML" que se ingresaron son válidos. Si usa su método (el código), puede tener XML mal formado que pasará la prueba. – Martin

+0

Consulte http://stackoverflow.com/questions/1072158/validate-xml-syntax-only-in-c – Graviton

+0

¿Está escribiendo esto usted mismo? No entiendo por qué lo estás escribiendo de una manera que no puedes interpretar las áreas correctamente, entonces ...? –

Respuesta

3

Una posibilidad es mezclar ambas soluciones. Puede usar su método redact e intentar cargarlo (dentro del if). De esta forma, solo intentarás cargar lo que probablemente sea un xml bien formado y descartarás la mayoría de las entradas que no sean xml.

+0

Buena idea, gracias – si618

+0

He marcado esto como la respuesta más adecuada, porque creo que resuelve mi problema de la manera más eficiente En la mayoría de los casos, StartsWith filtrará los datos que no son xml, y para situaciones excepcionales como describe Ira Baxter, la captura de XmlException los resolverá. – si618

8

Si vas a aceptar no XML bien formado, en primer lugar, creo que agarrar la excepción es el La mejor manera de manejarlo.

+0

Te gané por 2 segundos, ¡ja! – Martin

+0

¡Ja, ja! ¡Tú ganas! – lod3n

+0

También podría editar la publicación y poner "¡Primero!" – Spence

2

Si su objetivo es la fiabilidad, la mejor opción es usar XmlDocument.LoadXml para determinar si es XML válido o no. Un análisis completo de los datos puede ser costoso, pero es la única forma confiable de decir si es XML válido o no. De lo contrario, cualquier carácter que no examine en el búfer podría causar que los datos sean XML ilegales.

+0

No creo que 'XmlDocument' sea una buena opción aquí; no necesita DOM, simplemente para validar. Parece que 'XmlReader' y' try {while (reader.Read();} catch (XmlException ex) {...} 'sería un enfoque más ligero. –

+0

@Pavel, pero también tengo que modificar el Xml para redactar los datos, de ahí la necesidad de XmlDocument. – si618

+0

De acuerdo, pero si combino los enfoques (según la idea de Samuel), entonces debería capturar el 99% del texto sin formato con el código StartsWith y EndsWith, y dejar el otro 1% para atrapar si LoadXml lanza XmlException. – si618

0

Si el XML contiene ningún elemento raíz (es decir, que es un fragmento de XML, no es un documento completo), a continuación, la siguiente sería la muestra perfectamente válido, así - pero no coincidiría con su detector:

foo<bar/>baz 

De hecho, cualquier cadena de texto sería un fragmento válido de XML (¡considere si el documento XML original era solo el elemento raíz que envolvía el texto y quita las etiquetas de los elementos raíz)!

1

Depende de la precisión de la prueba que desee. Teniendo en cuenta que ya no tiene el < xml oficial, ya está tratando de detectar algo que no es XML. Lo ideal sería analizar el texto mediante un analizador XML completo (como sugiere LoadXML); cualquier cosa que rechace no es XML. La pregunta es, ¿te importa si aceptas una cadena que no sea XML? Por ejemplo, ¿estás bien con la aceptación de

<the quick brown fox jumped over the lazy dog's back> 

como XML y despojarla? Si es así, tu técnica está bien. De lo contrario, debe decidir qué tan ajustada es la prueba que desea y codificar un reconocedor con ese grado de rigidez.

+0

Sí, ese es el tipo de cosas que temo golpear. – si618

1

¿Cómo le llegan los datos? ¿Cuál es el otro tipo de datos que lo rodean? Tal vez hay una mejor manera; quizás puedas poner en parcelas los datos que controlas y luego inferir que cualquier cosa que no esté dentro de esos tokens es XML, pero necesitaríamos saber más.

Al fallar una linda solución como esa, creo que lo que tienes está bien (para validar que comienza y termina con esos caracteres).

Necesitamos saber más sobre el formato de datos realmente.

0
try 
{ 
    XmlDocument myDoc = new XmlDocument(); 
    myDoc.LoadXml(myString); 
} 
catch(XmlException ex) 
{ 
    //take care of the exception 
} 
+1

Por supuesto, y esto se afirma en la pregunta. Pero capturar excepciones es costoso cuando sé que muchos de los datos no son xml. – si618

Cuestiones relacionadas