sed 또는 awk를 사용하여 XML 파일에서 검색 및 바꾸기

sed 또는 awk를 사용하여 XML 파일에서 검색 및 바꾸기

그래서 bash 쉘 스크립트를 통해 XML 파일을 조작해야 하는 작업이 있습니다.

다음과 같이 진행하세요:

  1. XML 파일의 값을 쿼리합니다.
  2. 값을 가져오고 이를 상호 참조하여 목록에서 새 값을 찾습니다.
  3. 다른 요소의 값을 새로운 값으로 바꿉니다.

다음은 불필요한 정보가 제거된 XML의 예입니다.

<fmreq:fileManagementRequestDetail xmlns:fmreq="http://foobar.com/filemanagement">
      <fmreq:property>
         <fmreq:name>form_category_cd</fmreq:name>
         <fmreq:value>Memos</fmreq:value>
      </fmreq:property>
      <fmreq:property>
         <fmreq:name>object_name</fmreq:name>
         <fmreq:value>Correspondence</fmreq:value>
      </fmreq:property>
</fmreq:fileManagementRequestDetail>

object_name 아래의 값 요소에서 값을 가져와 상호 참조한 다음 form_category_cd 값 요소 아래의 값을 새 값으로 바꿔야 합니다.

따라서 object_name -> 값이 Correspondence인 경우 form_category_cd -> 값은 YYZ여야 할 수 있습니다.

문제는 우리 운영팀이 우리가 가지고 있는 도구만 사용하도록 제한하기 때문에 서버에서 사용 가능한 도구만 사용할 수 있다는 것입니다. xmllint 업데이트를 위한 싸움이 있었지만 나중에 거부되었습니다. 내가 사용하고 있는 버전은 --xpath를 지원하지 않습니다. 좋은 날에도 문제가 있을 거라 확신합니다. 또한 제가 사용 가능한 버전은 네임스페이스를 지원하지 않으므로 xmllint가 종료됩니다.

나는 sed를 시도했지만 내가 시도한 모든 테스터는 잘 작동했지만 정규식이 마음에 들지 않는 것 같습니다.

정규식:

(<fmreq\:name>object_name<\/fmreq\:name>)(?:\n\s*)(<fmreq\:value>)(.*)(<\/fmreq\:value>)

그룹 #3을 가져와야 하는데 sed가 이를 반환하지 않습니다. 대신 XML 파일의 전체 내용을 반환합니다.

sed -e 's/\(<fmreq\:name>object_name<\/fmreq\:name>\)\(?:\n\s*\)\(<fmreq\:value>\)\(.*\)\(<\/fmreq\:value>\)/\3/' < c3.xml 

나는 awk/gawk에 대해 잘 알지 못하기 때문에 그것들도 알아내려고 노력하고 있지만 찾을 수 있다면 해결책에 열려 있습니다.

awk/gawk 솔루션을 갖고 싶고, 단지 상사가 오래된 awk 팬이기 때문에 그를 기쁘게 해주기 위해 노력하고 싶지만, 난감하기 때문에 얻을 수 있는 것을 택하겠습니다.

이번에도 나는 가지고 있는 도구를 사용해야 했고 새로운 것을 설치할 수 없었습니다.

답변1

사용XML 스타:

$ xml ed -u '//fmreq:property[fmreq:name="object_name"]/preceding-sibling::fmreq:property/fmreq:name' -v YYZ file.xml
<?xml version="1.0"?>
<fmreq:fileManagementRequestDetail xmlns:fmreq="http://foobar.com/filemanagement">
  <fmreq:property>
    <fmreq:name>YYC</fmreq:name>
    <fmreq:value>Memos</fmreq:value>
  </fmreq:property>
  <fmreq:property>
    <fmreq:name>object_name</fmreq:name>
    <fmreq:value>Correspondence</fmreq:value>
  </fmreq:property>
</fmreq:fileManagementRequestDetail>

XPath의 첫 번째 부분 은 노드를 //fmreq:property[fmreq:name="object_name"]찾고 , 이 비트는 이전 노드의 노드를 찾습니다 .<fmreq:name>object_name</fmreq:name>/preceding-sibling::fmreq:property/fmreq:name<fmreq:name><fmreq:property>

답변2

귀하의 명령에 몇 가지 문제가 있다고 생각합니다 sed.

  • 해당 옵션을 사용하지 않으므로 -n기본적으로 sed각 입력 줄은 출력으로 인쇄됩니다( sed명령으로 수정될 수 있음).

  • 마지막 매개변수는 파일명으로 인식되므로 < c3.xml리다이렉트 할 필요가 없습니다 .sed

  • sed다중 라인 매칭에는 적합하지 않습니다. 예시 보기여기.

귀하의 예에서는 다음이 작동하는 것 같습니다.

sed -n "/<fmreq:name>object_name<\/fmreq:name>/ {n;p}" c3.xml | sed "s/^\s*<fmreq:value>\(.*\)<\/fmreq:value>/\1/g"

아니면 sed한 번만 호출하세요.

sed -n "/<fmreq:name>object_name<\/fmreq\:name>/ {n;s/^\s*<fmreq:value>\(.*\)<\/fmreq:value>/\1/g;p}" c3.xml

이 명령의 기능은 다음과 같이 분류됩니다.

  • 이 옵션은 라인 처리 후 패턴 공간을 인쇄하지 않도록 -n지시합니다 . 따라서 이 작업을 수행하려면 명령을 명시적으로 사용해야 sed합니다 .p

  • /regex/sed일치하는 행의 명령만 실행되도록 지시합니다 regex.

  • sed명령은 n패턴 공간의 내용을 관심 있는 값이 포함된 다음 입력 줄로 바꿉니다.

  • sed명령은 s/regex/replacement/패턴 공간의 첫 번째 항목을 .regexreplacement

  • sed명령은 p행을 인쇄합니다.

관련 정보