XML 명령 줄 (쉘 스크립트) 조작


9

셸 스크립트의 명령 줄에서 XML을 조작하는 방법은 무엇입니까?

표 형식의 데이터를 조작하거나 환경 변수를 대체하거나 텍스트 조각을 정규식으로 바꾸는 명령이 많이 있지만 XML에 대해서는 아무것도 찾지 못했습니다.

내 빌드 스크립트는 xml 문서의 기본 태그 내에 내용이 포함 된 태그를 삽입해야하며 OS에 Java, perl 또는 python을 설치하기 위해 과도한 노력을 기울입니다 (스크립트는 docker 이미지가있는 gitlab에서 수행되므로 maven : 3.5-jdk-8 이미지로 제공되는 도구를 사용한 제 직업은 꿈일 것입니다).

내 빌드 스크립트에서는 그것이 악하기 때문에 작동하지만 sed로 XML을 조작하고 싶지 않습니다 .

예 : 다음 XML이 있습니다.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>  
  <!-- a lot of other tags-->
</project>  

그리고 다음 블록을 삽입하고 싶습니다.

<distributionManagement>
    <repository>
        <id>private-releases</id>
        <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
</distributionManagement>

프로젝트 태그 내부 (그리고 시작 또는 끝에 있는지 여부는 중요하지 않습니다.


입력 XML 및 예상 출력 게시
— RomanPerekhrest

따라서 특정 요구 사항은 주요 스크립팅 언어로 구현되지 않은 독립형 C 또는 C ++ (또는 기타 컴파일 된) 유틸리티로 명령 줄에서 호출 할 수있는 XML 파서에 대한 것입니까?
— Kusalananda

@Kusalanda 나는 docker 컨테이너 내에서 scipts를 실행 중이라고 지정 했으므로 가능한 한 docker 이미지에 조금만 추가하는 것이 가장 중요합니다.
— 9ilsdx 9rvj 0lo

maven과 jdk가있는 이미지가 있다면 Java가 가장 좋은 옵션처럼 들립니다 .... 왜이 경우 Java 헤비급을 고려합니까?
— Daniel Pryden

스택 오버플로와 태그 지정에 대해이 질문을 maven하는 것이 좋습니다 .Maven 자체에서 수행하려는 작업을 수행하는 더 좋은 방법이 있다고 생각합니다.
— Daniel Pryden

답변:


10

XMLStarlet는 ( http://xmlstar.sourceforge.net/overview.php ) C 및 용도에 기록 libxml2하고 libxslt.

주어진 XML 문서

<?xml version="1.0"?>
<root>
  <tag>data</tag>
</root>

를 root사용하여 삽입 될 수 있는 서브 노드

xml ed -s '/root' -t elem -n 'newtag' -v 'newdata' file.xml

어떤 생산

<?xml version="1.0"?>
<root>
  <tag>data</tag>
  <newtag>newdata</newtag>
</root>

많은 것을 삽입 ( file.xml여기 상단 의 원본 사용 ) :

xml ed -s '/root' -t elem -n 'newtag' \
       -s '/root/newtag' -t elem -n 'subtag' -v 'subdata' file.xml

이것은 생산

<?xml version="1.0"?>
<root>
  <tag>data</tag>
  <newtag>
    <subtag>subdata</subtag>
  </newtag>
</root>

질문의 예 :

xml ed -N x="http://maven.apache.org/POM/4.0.0" \
       -s '/x:project' -t elem -n 'distributionManagement' \
       -s '/x:project/distributionManagement' -t elem -n 'repository' \
       -s '/x:project/distributionManagement/repository' -t elem -n 'id' \
         -v 'private-releases' \
       -s '/x:project/distributionManagement/repository' -t elem -n 'url' \
         -v 'https://my.private.server.com/nexus/repository/maven-releases/' \
    file.xml

결과:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!-- a lot of other tags-->
  <distributionManagement>
    <repository>
      <id>private-releases</id>
      <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
  </distributionManagement>
</project>

이전에 준비된 XML 파일을 XML의 위치에 삽입

질문에서 원본 XML을 가정에 file.xml새로운에 가야 추가 비트 distributinManagement노드에있는 new.xml(그러나 하지 노드 태그 자체), 하나는 다음을 수행 할 수 삽입 할 new.xml루트 노드에서 :

xml ed -N x="http://maven.apache.org/POM/4.0.0" \
       -s '/x:project' -t elem -n 'distributionManagement' \
       -v "$(<new.xml)" file.xml | xml unesc | xml fo

XMLStarlet은 <및 등의 이스케이프가 필요한 데이터를 자동으로 이스케이프합니다 >. xml unesc비트 을 이스케이프 삽입 된 데이터 (또는 실제로 문제가되지 않을 수도 전체 문서를 언 이스케이프) 및 xml fo재 포맷 생성 XML 문서.

결과는

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!-- a lot of other tags-->
  <distributionManagement>
    <repository>
      <id>private-releases</id>
      <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
  </distributionManagement>
</project>

나는 이런 식으로하는 것이 조금 불편하다. 그러나 "작동한다".

StackOverflow 에서이 관련 질문을 참조하십시오 : https : //.com/questions/29298507/xmlstarlet-xinclude-xslt


하나 이상의 태그를 삽입하는 경우 구문이 상당히 길지만 흥미로워 보입니다. 우분투에서만 이름이 'xmlstarlet'입니다. 내용이 유효한 XML이라고 가정하고 다른 파일의 내용을 태그로 삽입 할 수 있습니까?
— 9ilsdx 9rvj 0lo

@ 9ilsdx9rvj0lo 업데이트 된 답변보기
— Kusalananda

"실제로 문서 전체를 이스케이프 처리하므로 문제가 될 수도 있고 아닐 수도 있습니다." 그래도 거대한 문제, 모든 기존의 & amp; 인코딩되지 않아 XML이 더 이상 유효하지 않습니다. (
— rob

1

그 목적으로 OS에 java, perl 또는 python을 설치하는 것이 과도하다는 것을 알았습니다 (제 스크립트는 docker 이미지와 함께 gitlab에서 수행되므로 maven : 3.5-jdk-8 이미지에서 사용할 수있는 도구로 작업을 수행하는 것은 꿈입니다).

아마도 여전히 과잉이지만 컨테이너의 크기에만 관심이 있다면 Lua 또는 Guile과 같은 매우 가벼운 언어를 사용할 수 있습니다.

루아 문서에서 :

응용 프로그램에 Lua를 추가해도 문제가 해결되지 않습니다. 소스 코드와 문서가 포함 된 Lua 5.3.4 용 tarball은 297K 압축 및 1.1M 비 압축을 사용합니다. 이 소스에는 약 24000 줄의 C가 포함되어 있습니다. 64 비트 Linux에서 모든 표준 Lua 라이브러리로 구축 된 Lua 인터프리터는 246K를, Lua 라이브러리는 421K를 사용합니다.


팁 덕분에 LUA를 maven 컨테이너에 추가하는 것을 고려해 볼 가치가 있습니다.
— 9ilsdx 9rvj 0lo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.