2008-11-14 17 views
12

Tengo un resultado XML bastante grande de una aplicación. Necesito procesarlo con mi programa y luego retroalimentarlo al programa original. Hay piezas en este XML que deben ser completadas y reemplazadas. La parte interesante se ve así:No se puede hacer que la expresión regular funcione correctamente con multiline

<sys:customtag sys:sid="1" sys:type="Processtart" /> 
    <sys:tag>value</sys:tag> 
    here are some other tags 
    <sys:tag>value</sys.tag> 
<sys:customtag sys:sid="1" sys:type="Procesend" /> 

y el documento contiene varias piezas como esta.

Necesito obtener todas las piezas XML dentro de estas etiquetas para poder hacer modificaciones en ella. Escribí una expresión regular para conseguir esas piezas, pero no funciona:

XmlDocument xmlDoc = new XmlDocument(); 
xmlDoc.Load(@"output.xml"); 
Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>", RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant); 
MatchCollection matches = regExp.Matches(xmlDoc.InnerXml); 

si lo dejo toda la materia en una línea y llamar a esta expresión regular sin la opción de varias líneas, se la encuentra cada ocurrencias. Al dejar el archivo tal como está y establecer la opción de líneas múltiples, no funciona. ¿Cuál es el problema? ¿Qué debería cambiar? ¿O hay alguna manera más fácil de obtener las partes XML entre estas etiquetas sin regexp?

Respuesta

41

Creo que la opción de usar es RegexOptions.Singleline en lugar de RegexOptions.Multiline (src). permitir (.) coincidir con nuevas líneas debería funcionar en su caso.

... el modo donde el punto también coincide con los saltos se llama "modo de una sola línea". Esto es un poco desafortunado, porque es fácil mezclar este término con "modo multilínea". El modo multilínea solo afecta a los anclajes, y el modo de línea única solo afecta al punto ... Al usar las clases regex del .NET framework, activa este modo especificando RegexOptions.Singleline, como en Regex.Match ("cadena "," regex ", RegexOptions.Singleline).

+0

Eso es todo, gracias. También me refería a multiline = multi line mode. – Biri

4

RegExp es una herramienta pobre para xml ... es posible que no salientes cargarlo en un XDocument/XmlDocument y utilizar XPath? Si clarifica las modificaciones que desea realizar, espero que podamos completar los espacios en blanco ... los espacios de nombres son probablemente lo principal para que sea complejo en este caso, así que solo necesitamos usar un XmlNamespaceManager.

Aquí hay un ejemplo que es, es cierto, más complejo que una simple expresión regular - sin embargo, yo esperaría que lidiar mucho mejor con los matices de xml:

string xml = @"<foo xmlns:sys=""foobar""><bar/><bar><sys:customtag sys:sid=""1"" sys:type=""Processtart"" /> 
<sys:tag>value</sys:tag> 
here are some other tags 
<sys:tag>value</sys:tag> 
<sys:customtag sys:sid=""1"" sys:type=""Procesend"" /></bar><bar/></foo>"; 

    XmlDocument doc = new XmlDocument(); 
    doc.LoadXml(xml); 
    XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable()); 
    mgr.AddNamespace("sys", "foobar"); 
    var matches = doc.SelectNodes("//sys:customtag[@sys:type='Processtart']", mgr); 
    foreach (XmlElement start in matches) 
    { 
     XmlElement end = (XmlElement) start.SelectSingleNode("following-sibling::sys:customtag[@sys:type='Procesend'][1]",mgr); 
     XmlNode node = start.NextSibling; 
     while (node != null && node != end) 
     { 
      Console.WriteLine(node.OuterXml); 

      node = node.NextSibling; 
     } 
    } 
+0

He buscado las opciones de XPath pero no he encontrado nada que me devuelva el contenido XML a las etiquetas, que no están relacionadas con XML (es decir, no son etiquetas de inicio y cierre entre sí desde el punto de XML). Tal vez tienes una idea? – Biri

+0

Bueno, xml está destinado a ser usado como árbol ... una opción simple sería usar ... - pero voy a echar un vistazo rápido. .. –

+0

Sí, puedo manejar eso, pero desafortunadamente el XML proviene de una aplicación que no puedo cambiar, y tengo que devolverlo a la misma aplicación en este formato. No puedo cambiar las etiquetas XML dentro. – Biri

4

El carbón de expresiones regulares "" nunca coincide con una línea nueva, incluso con la opción MultiLine establecida. en su lugar, debe usar [\s\S] u otra combinación con coincidencias.

La opción MultiLine sólo modifica el comportamiento de^(COMIENZO-de-línea en lugar fo COMIENZO-de-cadena) y $ (fin de línea en lugar de al final de la cadena)

Por cierto: En efecto , la expresión regular no es la forma correcta de escanear un código HTML ...

4

Si aún tiene problemas con esto, puede ser porque está utilizando Y con sus RegexOptions en lugar de O.

Este código es incorrecto y pasará a cero como el segundo parámetro al constructor:

Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>", 
RegexOptions.Multiline & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant); 

Este código es correcto (por lo que el uso de banderas múltiples RegexOptions):

Regex regExp = new Regex(@"<sys:customtag(.*?)Processtart(.*?)/>(.*?)<sys:customtag (.*?)Procesend(.*?)/>", 
RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant); 
Cuestiones relacionadas