Alles entfernenKnoten != Tag-Wert

Alles entfernenKnoten != Tag-Wert

Ich weiß, dass XML-Parser hier die ideale Lösung sind, aber es sind keine verfügbar oder können zu meiner Umgebung hinzugefügt werden.

Nehmen wir XML, das der folgenden Struktur folgt:

<CONTAINER>
  <FOLDER NAME="I_RS_INT">
  </FOLDER>
  <FOLDER NAME="I_R_INR">
  </FOLDER>
  <FOLDER NAME="I_RS_TRN">
  </FOLDER>
</CONTAINER>

In einem Bash-Skript möchte ich alle Knoten entfernen, bei denen die <FOLDER NAME=Übereinstimmungen *RS*ODER alle Knoten entfernen, bei denen<FOLDER NAME != $var_folder

Jede Hilfe ist herzlich willkommen!

Antwort1

Das hier sollte genügen:

cat /tmp/xml  | sed -e '/<FOLDER NAME=.*RS.*>/ { N; d; }'

Für jede Zeile, die dem Muster zwischen den beiden /Zeichen entspricht, wird der Code in den {} ausgeführt. N nimmt auch die nächste Zeile in den Musterbereich auf, und dann löscht d das Ganze, bevor mit der nächsten Zeile fortgefahren wird. Dies funktioniert in jedem POSIX-kompatiblen sed.

Versuchen Sie Folgendes, um alle Zeilen zwischen <FOLDER NAME=.*RS.*>und zu entfernen </FOLDER.>:

 awk '/<FOLDER NAME=.*RS.*>/,/<\/FOLDER>/ {next} {print}' xmlfile

Der nextBefehl stoppt die Verarbeitung der aktuellen Übereinstimmung. Folgen Sie darauf mit einem einfachen print.

Antwort2

Sie sollten dies mit einem XML-Parser tun. Verwenden Sie beispielsweiseXMLStarletauf der Kommandozeile:

$ xmlstarlet ed -d '/CONTAINER/FOLDER[contains(@NAME, "RS")]' data.xml
<?xml version="1.0"?>
<CONTAINER>
  <FOLDER NAME="I_R_INR">
  </FOLDER>
</CONTAINER>

Oder,

$ var="I_R_INR"
$ xmlstarlet ed -d "/CONTAINER/FOLDER[@NAME != '$var']" data.xml
<?xml version="1.0"?>
<CONTAINER>
  <FOLDER NAME="I_R_INR">
  </FOLDER>
</CONTAINER>

Beachten Sie, dass diese beiden nicht gleichwertig sind, da das erste Beispiel eine Teilzeichenfolgenübereinstimmung durchführt, während das zweite eine exakte Übereinstimmung durchführt.


Mit der xqHülle drumherum jq:

$ xq -x --arg substring "RS" 'del(.CONTAINER.FOLDER[] | select(."@NAME" | contains($substring)))' file.xml
<CONTAINER>
  <FOLDER NAME="I_R_INR"></FOLDER>
</CONTAINER>
$ xq -x --arg name "I_R_INR" 'del(.CONTAINER.FOLDER[] | select(."@NAME" != $name))' file.xml
<CONTAINER>
  <FOLDER NAME="I_R_INR"></FOLDER>
</CONTAINER>

Antwort3

OK, im Ernst - XML ​​mit regulären Ausdrücken zu parsen istschlechte Nachrichten. XML ist KEINE reguläre Sprache, daher kann kein regulärer Ausdruck damit richtig umgehen. Alles, was Sie schreiben, wird dadurch fehlerhaft und instabil.

XMLEs gibt jedoch etwas Ähnliches wie reguläre Ausdrücke, genannt xpath.

Um Ihr Problem anzugehen, würde ich es folgendermaßen machen:

#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
#process the file as XML
my $twig = XML::Twig -> parsefile ( 'your_file.xml' );

#iterate 'FOLDER' elements
foreach my $folder ( $twig -> get_xpath ('//FOLDER' ) ) {
   #delete any that regex match /RS/
   if ( $folder -> att('NAME') =~ m/RS/ ) { 
      $folder -> delete;
   }
}

#print the result. 
$twig -> set_pretty_print('indented_a');
$twig -> print;

Antwort4

sed -r '/<FOLDER NAME=.*RS.*>/{ :X N; /<\/FOLDER>/d; bX }' file
<CONTAINER>
  <FOLDER NAME="I_R_INR">
  </FOLDER>
</CONTAINER>

verwandte Informationen