Как найти n-й символ '<', содержащий слово, в XML-подобном текстовом файле?

Отображение программ графического интерфейса Unix через X-сервер . Cygwin не запускает X-сервер автоматически. Вам необходимо установить пакеты xorg-server и xinit , а запустить startxwin .

2
15.02.2018, 12:41
5 ответов

grep +awksolución:

grep -Eo '<[^<>]+>' input.xml | awk '{ gsub(/[<>]/,""); printf "%-3s - %s\n", NR, $0 }'

La salida:

1   - note
2   - to
3   - /to
4   - from
5   - /from
6   - heading
7   - /heading
8   - body
9   - /body
10  - /note

O con un solo comando GNUawk:

awk -v FPAT='</?[^<>]+>' '{ for(i=1;i<=NF;i++) printf "%-3s - %s\n", ++c, $i }' input.xml
2
27.01.2020, 21:49

aquí hay un método bastante fácil para responder a su pregunta sobre la extracción de etiquetas de apertura... pero su ejemplo pregunta también por las de cierre... esto parece una tontería porque una cerrada está abierta, por supuesto... ¿realmente también necesita los cerrados, pero si desea controlar el formato xml, use una herramienta como xmllint....

bash-4.4$ cat > toto
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note> 
bash-4.4$ awk '{
match($0,/<\/.*>/); 
b=substr($0,RSTART,RLENGTH); 
 if(b)
    {a[++i]=b}
     } 
END{
  {for(k in a)
    {c[a[k]]=k}
 } 
 {for(u in c)
  {gsub(/\//,X,u);print u}
 }
   }' toto | sed 's/</- /;s/>//' | cat -n
     1  - body
     2  - note
     3  - to
     4  - heading
     5  - from
bash-4.4$ rm toto

o para guardar todo y usar sed solo por diversión:

bash-4.4$ sed -e  's/>\(.*\)</></;s/>/\n/g;s/</- /g' toto | sed '/^$/ d' | cat -n
     1  - note
     2  - to
     3  - /to
     4  - from
     5  - /from
     6  - heading
     7  - /heading
     8  - body
     9  - /body
    10  - /note
    11   
bash-4.4$ 
2
27.01.2020, 21:49

Nota :Esta respuesta se escribió antes de que el usuario explicara que el XML no estaba bien formado. Lo dejo aquí ya que posiblemente pueda ayudar a otros.


XMLStarlet es capaz de producir la estructura de elementos de documentos XML:

$ xml el file.xml
note
note/to
note/from
note/heading
note/body

Esto es diferente de su resultado esperado, pero puede ser suficiente para lo que desea lograr.

También puede convertir el XML a PYX, que muestra las etiquetas de apertura y cierre en líneas separadas:

$ xml pyx file.xml
(note
-\n
(to
-Tove
)to
-\n
(from
-Jani
)from
-\n
(heading
-Reminder
)heading
-\n
(body
-Don't forget me this weekend!
)body
-\n
)note

A partir de esto, es fácil obtener exactamente el resultado que está buscando:

$ xml pyx file.xml | sed -n -e 's/^(//p' -e 's/^)/\//p'| nl
     1  note
     2  to
     3  /to
     4  from
     5  /from
     6  heading
     7  /heading
     8  body
     9  /body
    10  /note

Las instrucciones sedeliminan las líneas que no comienzan con (o )y reemplazan estos caracteres de acuerdo con cómo lo especificó en la pregunta. La utilidad nlpone el número de línea en las líneas.


XMLStarlet a veces se instala como xmlstarleten lugar de xml.

3
27.01.2020, 21:49
$ awk -F"[<>]" '{for(i=2;i<=NF;i+=2){print ++j" - "$i}}' input.xml
1 - note
2 - to
3 - /to
4 - from
5 - /from
6 - heading
7 - /heading
8 - body
9 - /body
10 - /note
3
27.01.2020, 21:49

Aquí hay una solución XQuery en caso de que desee algo que funcione en CUALQUIER XML, incluso XML incómodo que contiene comentarios, DTD, elementos de autocierre -, etc.

declare function local:f($e) {
  $e / (name(), local:f(*), ('/' || name()))
};
for $tag at $p in local:f(/*)
return ($p || ' - ' || $tag || '&#xa;')
1
27.01.2020, 21:49

Теги

Похожие вопросы