sed 도구를 사용하지 않고 (하위 태그의) 패턴을 찾고 XML 파일에서 전체 상위 태그를 바꿉니다.

sed 도구를 사용하지 않고 (하위 태그의) 패턴을 찾고 XML 파일에서 전체 상위 태그를 바꿉니다.

정규식을 사용하여 하위 태그의 패턴을 찾고 전체 상위 태그를 바꾸는 방법이 있습니까? 저는 그래픽 환경이 없는 Linux 서버에서 작업하고 있습니다.

다음과 같은 XML이 있습니다.

<?xml version="1.0" encoding="UTF-8"?>  
<bookstore>  
  <book category="COOKING">  
    <title lang="en">Everyday Italian</title>  
    <author>Giada De Laurentiis</author>  
    <year>2005</year>  
    <price>30.00</price>  
  </book>  
  <book category="CHILDREN">  
    <title lang="en">Harry Potter</title>  
    <author>J K. Rowling</author>  
    <year>2005</year>  
    <price>29.99</price>  
  </book>  
  <book category="WEB">  
    <title lang="en">Learning XML</title>  
    <author>Erik T. Ray</author>  
    <year>2003</year>  
    <price>39.95</price>  
  </book>  
</bookstore>  

패턴을 찾을 수 있는 쉘 스크립트가 필요합니다.

<author>J K. Rowling</author>

그런 다음 전체 블록을 교체합니다.

  <book category="CHILDREN">  
    <title lang="en">Harry Potter</title>  
    <author>J K. Rowling</author>  
    <year>2005</year>  
    <price>29.99</price>  
  </book>  

그리고:

  <book category="CHILDREN">  
    <title lang="en">Hamlet</title>  
    <author>William Shakespeare</author>  
  </book>

마침내 얻었습니다 :

<?xml version="1.0" encoding="UTF-8"?>  
<bookstore>  
  <book category="COOKING">  
    <title lang="en">Everyday Italian</title>  
    <author>Giada De Laurentiis</author>  
    <year>2005</year>  
    <price>30.00</price>  
  </book>  
  <book category="CHILDREN">  
    <title lang="en">Hamlet</title>  
    <author>William Shakespeare</author>  
  </book>  
  <book category="WEB">  
    <title lang="en">Learning XML</title>  
    <author>Erik T. Ray</author>  
    <year>2003</year>  
    <price>39.95</price>  
  </book>  
</bookstore> 

와 마찬가지로 와 사이의 모든 텍스트 또는 코드에 대한 와일드카드 <book*<author>J K. Rowling</author>*</book>는 어디에 있습니까?*<book<author>...

Perl을 사용하여 다음 논리적 단계를 고려하는 아이디어가 있습니다.

  1. 검색 패턴이 위치한 라인 번호
  2. 상위 블록의 열기 및 닫기 태그의 줄 번호를 식별합니다.
  3. 이 줄 내의 모든 내용을 삭제하십시오.
  4. 이 줄 안에 새 블록을 추가하세요.

그러나 가능합니다. 저는 첫 번째 접근 방식을 선호합니다.

답변1

내가 선호하는 방법은 종종 xmlstarletXML 데이터를 사용하여 작업하는 것입니다. 편집해야 하는 하위 트리를 참조하는 xmlstarlet변수를 선언합니다.$book

xmlstarlet <682660.xml ed                                               \
    --var book '//book[author="J K. Rowling"]'                          \
    --update '$book' --value ''                                         \
    --update '$book/@category' --value 'CHILDREN'                       \
    --subnode '$book' --type 'elem' --name 'title'  --value 'Hamlet'    \
    --subnode '$book/title' --type attr --name 'lang' --value 'en'      \
    --subnode '$book' --type 'elem' --name 'author' --value 'William Shakespeare'

산출

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="COOKING">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
  <book category="CHILDREN">
    <title lang="en">Hamlet</title>
    <author>William Shakespeare</author>
  </book>
  <book category="WEB">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>

관련 <book/>하위 트리를 삭제하고 새 하위 트리를 추가할 수도 있지만 이렇게 하면 순차 처리가 중단될 수 있으므로 여기서는 그렇게 하지 않았습니다.

답변2

구조화된 문서 형식으로 작업할 때는 이러한 형식과 함께 작동하도록 설계된 도구를 사용하십시오. 정규식은 주로 텍스트를 일치시키는 데 사용되며 XML 문서는 실제로 텍스트가 아니지만 특정 방식으로 구조화된 데이터입니다(줄 바꿈 등이 항상 중요한 것은 아닙니다). 다시 말하지만 sed이는 텍스트 줄을 처리하기 위한 도구이지만 일반적으로 XML은 그렇지 않습니다.

xq다음에서 사용https://kislyuk.github.io/yq/

xq -x '.book as $new | input |
    (
        .bookstore.book[] |
        select(.author == "J K. Rowling")
    ) |= $new' insert.xml file.xml

XML과 삽입할 요소를 xqJSON으로 변환하는 데 사용됩니다. 그런 다음 생성된 JSON 문서에 특정 표현식을 적용하여 배열의 각 항목을 추출합니다. 그런 다음 정확히 동일한 필드가 있는 해당 배열의 모든 요소는 읽은 요소로 대체됩니다.bookstoreinsert.xmljq.bookstore.book.authorJ K. Rowlinginsert.xml

더 자세히 말하자면, 새 객체의 내용을 .book내부 변수라는 내부 변수로 읽어온 $new다음 를 호출하여 기본 문서를 가져옵니다 input. 이 select()명령문은 .bookstore.book배열의 각 개별 요소에 대해 작동하며 특정 작성자가 있는 요소를 추출합니다. 결과는 일치하는 항목에 대한 여러 "경로"입니다 book. (업데이트 연산자)를 사용하여 이전에 생성된 값 |=으로 업데이트합니다 $new.

파일을 통하지 않고 명령줄에서 새 XML을 제공하려면 다음 설명서를 사용하세요.

xq -x '.book as $new | input |
    (
        .bookstore.book[] |
        select(.author == "J K. Rowling")
    ) |= $new' - file.xml <<'NEW_XML'
<book category="CHILDREN">
  <title lang="en">Hamlet</title>
  <author>William Shakespeare</author>
</book>
NEW_XML

입력 파일 이름은 insert.xml명령줄에서 대시로 대체됩니다.

귀하의 질문에 있는 데이터를 바탕으로 결과는 다음과 같습니다.

<bookstore>
  <book category="COOKING">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
  <book category="CHILDREN">
    <title lang="en">Hamlet</title>
    <author>William Shakespeare</author>
  </book>
  <book category="WEB">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>

이 유틸리티는 해당 (또는) 옵션을 사용하는 경우 xq내부 편집을 활성화합니다 .--in-place-i


참고로 xqXML은 다음 내부 JSON 표현으로 변환된 후 다음을 통해 처리됩니다 jq.

{
  "bookstore": {
    "book": [
      {"@category":"COOKING","title":{"@lang":"en","#text":"Everyday Italian"},"author":"Giada De Laurentiis","year":"2005","price":"30.00"},
      {"@category":"CHILDREN","title":{"@lang":"en","#text":"Harry Potter"},"author":"J K. Rowling","year":"2005","price":"29.99"},
      {"@category":"WEB","title":{"@lang":"en","#text":"Learning XML"},"author":"Erik T. Ray","year":"2003","price":"39.95"}
    ]
  }
}

삽입할 데이터는 동등한 내용으로 변환됩니다.

{
  "book": {
    "@category": "CHILDREN",
    "title": {
      "@lang": "en",
      "#text": "Hamlet"
    },
    "author": "William Shakespeare"
  }
}

관련 정보