Tengo un archivo xml en el siguiente formato

<starttag name="AAA" >
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="YYY"/>
</starttag>
<starttag name="BBB" >
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="XXX"/>
</starttag>
<starttag name="CCC" >
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="XXX"/>
    <innertag name="XXX" value="YYY"/>
</starttag>
..
..
..

Quiero extraer todos los atributos de nombre de la etiqueta de inicio cuya etiqueta interna tenga el valor YYY.

Entonces, en el archivo anterior, la salida será AAA y CCC. Solo puedo usar la coincidencia de expresiones regulares. Supongo que es posible usar lookaheads pero no puede crear patrones de expresiones regulares para multilíneas. Sé cómo usar expresiones regulares para una sola línea e intenté usar lo mismo con esto también, pero no obtuve los resultados esperados. Cualquiera que avance en esto.

Editar: aunque he puesto un ejemplo xml, pero en realidad estoy tratando de conocer la coincidencia de expresiones regulares multilínea y estoy probando este archivo en el que estoy fallando. Evite las soluciones relacionadas con el análisis de XML.

Actualización : según la sugerencia de Steven, lo siguiente funcionó

pcregrep -M '<starttag name="([^"])*"[^>]*>(\s|<innertag[^>]*>)*<innertag name="[^"]*" value="YYY"\/>(\s|<innertag[^>]*>)*<\/starttag>' file.xml

grep -Pzo '<starttag name="([^"])*"[^>]*>(\s|<innertag[^>]*>)*<innertag name="[^"]*" value="YYY"\/>(\s|<innertag[^>]*>)*<\/starttag>' file.xml
0
Shashwat Kumar 28 ene. 2016 a las 16:19

2 respuestas

La mejor respuesta

Un analizador XML, especialmente uno que admita XPath, será mucho más fácil y estable, pero si realmente debe insistir en usar expresiones regulares, aquí hay un patrón que funcionará con la entrada de muestra que proporcionó:

<starttag name="([^"])*"[^>]*>(\s|<innertag[^>]*>)*<innertag name="[^"]*" value="YYY"\/>(\s|<innertag[^>]*>)*<\/starttag>

No va a funcionar con todas las variaciones de documentos XML bien formados, pero siempre que tengan un formato coherente como en su ejemplo, debería estar "bien".

De forma predeterminada, la expresión regular siempre captura en varias líneas. Hay una opción en la que puede decirle que solo procese una línea a la vez, pero generalmente no está activada de forma predeterminada. El único truco real es que el patrón . no coincide con los caracteres de nueva línea, por lo que si desea hacer coincidir cualquier carácter, incluidas las nuevas líneas, debe usar .|\n o un carácter negativo clase como [^>].

0
Steven Doggart 28 ene. 2016 a las 13:35

Considere usar XMLStarlet

"XMLStarlet es un conjunto de utilidades de línea de comandos (herramientas) que se pueden usar para transformar, consultar, validar y editar documentos y archivos XML usando un conjunto simple de comandos de shell de manera similar a lo que se hace para archivos de texto sin formato usando UNIX grep, sed , awk, diff, patch, join, etc. ".

1
neuhaus 28 ene. 2016 a las 13:31