Как удалить совпадающий блок после сопоставления шаблона - PullRequest
0 голосов
/ 24 июня 2019

Вот файл (названный как sample.xml):


<?xml version="1.0" encoding="UTF-8"?>
<configs>

    <blah1 value="ma">
      <tag3>100MB</tag3>
    </blah1>

    <blah1 value="ba">
      <tag3>20MB</tag3>
    </blah1>

     <blah2 value="*" version="1.0" result="true">
        <blah1 value="xyz">
          <blah1 value="uvw" result="true">
             <tag>4</tag>
          </blah1>
        </blah1>
     </blah2>

  <!-- This is tag with def value -->
  <blah2 value="*" version="2.0" result="true">
    <blah1 value="abc">
      <blah1 value="def" result="true">
        <tag2>on</tag2>
      </blah1>
    </blah1>
  </blah2>

</configs>

Найдя строку с value="def", удалите весь блок, начиная с тегов <blah2> to </blah2>

Я не знаком с sed паттерном удержания, но что-то, что я получил от Google, очень близко

sed -n '/<blah2.*>/,/<\/blah2>/{
                                  H
                                  /<\/blah2>/ { 
                                        s/.*//;x
                                       /def/d
                                       p 
                                  }
                               }' sample.xml

Ожидаемый результат:


<?xml version="1.0" encoding="UTF-8"?>
<configs>

    <blah1 value="ma">
      <tag3>100MB</tag3>
    </blah1>

    <blah1 value="ba">
      <tag3>20MB</tag3>
    </blah1>

     <blah2 value="*" version="1.0" result="true">
        <blah1 value="xyz">
          <blah1 value="uvw" result="true">
             <tag>4</tag>
          </blah1>
        </blah1>
     </blah2>

</configs>

Фактический результат (с указанным выше нерабочим седом):

     <blah2 value="*" version="1.0" result="true">
        <blah1 value="xyz">
          <blah1 value="uvw" result="true">
             <tag>4</tag>
          </blah1>
        </blah1>
     </blah2>

Ответы [ 3 ]

3 голосов
/ 24 июня 2019

Удалить второй тег blah2 с помощью xmlstarlet:

xmlstarlet edit --delete '//configs[blah2[2]/blah1/blah1[@value="def"]]/blah2[2]' file.xml

Вывод:

<?xml version="1.0" encoding="UTF-8"?>
<configs>
  <blah1 value="ma">
    <tag3>100MB</tag3>
  </blah1>
  <blah1 value="ba">
    <tag3>20MB</tag3>
  </blah1>
  <blah2 value="*" version="1.0" result="true">
    <blah1 value="xyz">
      <blah1 value="uvw" result="true">
        <tag>4</tag>
      </blah1>
    </blah1>
  </blah2>
</configs>

Если вы хотите редактировать файл на месте, добавьте опцию -L.


Объяснение используемых XPath :

//configs[blah2[2]/blah1/blah1[@value="def"]]/blah2[2]
|---A---| |-------------B------------------| |---C---|

A и B: путь к искомому атрибуту

A и C:путь к тегу, который нужно удалить

1 голос
/ 24 июня 2019

Это может сработать для вас (GNU sed):

sed '/<blah2.*>/{:a;N;/<\/blah2.*>/!ba;/value="def"/d}' file

Если строка содержит <blah2.*>, собрать все строки до строки, содержащей <\/blah2.*>, затем проверить эти строки на наличие строки value="def" и, если она найдена, удалить эти строки.

0 голосов
/ 24 июня 2019

Поскольку вы довольны решением sed, вот лучшая (более понятная, более переносимая и т. Д.) Альтернатива, учитывая опубликованный пример ввода / вывода:

$ awk -v RS= -v ORS='\n\n' '!/value="def"/' file
<?xml version="1.0" encoding="UTF-8"?>
<configs>

    <blah1 value="ma">
      <tag3>100MB</tag3>
    </blah1>

    <blah1 value="ba">
      <tag3>20MB</tag3>
    </blah1>

     <blah2 value="*" version="1.0" result="true">
        <blah1 value="xyz">
          <blah1 value="uvw" result="true">
             <tag>4</tag>
          </blah1>
        </blah1>
     </blah2>

</configs>

Если это не все, что вам нужно, есть лучшая альтернатива awk для всего, что вам нужно, поскольку sed лучше всего подходит для выполнения s / old / new для отдельных строк.

...