Perl을 사용하여 xml 파일에서 줄을 변경하고 태그를 제거하시겠습니까?

Perl을 사용하여 xml 파일에서 줄을 변경하고 태그를 제거하시겠습니까?

줄을 변경하고 전체 태그를 제거해야 하는 XML 파일이 있으므로 (client_23.xml)Perl 스크립트를 생각해 냈습니다.

내 XML 파일에는 이와 같은 블록이 있습니다. <hello>collect_model = 1</hello>내 XML 파일에는 인스턴스가 하나만 있습니다.

<world>
    <hello>collect_model = 1</hello>
    <hello>enable_data = 0</hello>
    <hello>session_ms = 2*60*1000</hello>
    <hello>max_collect = string_integer($extract("max_collect"))</hello>
    <hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
    <hello>output('{')</hello>
</world>

해당 줄을 다음과 같이 변경해야 합니다. <hello>collect_model = 0</hello>따라서 전체 블록을 변경한 후 다음과 같아야 합니다.

<world>
    <hello>collect_model = 0</hello>
    <hello>enable_data = 0</hello>
    <hello>session_ms = 2*60*1000</hello>
    <hello>max_collect = string_integer($extract("max_collect"))</hello>
    <hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
    <hello>output('{')</hello>
</world>

두 번째는 동일한 XML 파일에서 전체 태그를 제거해야 한다는 것입니다.

<derta-config>
    <data-users>2000</data-users>
    <test-users>2000</test-users>
    <attributes>hello world</attributes>
    <client-types>Client1</model-types>
    <target>price.world</target>
</derta-config>

그래서 Perl을 사용하는 다음 쉘 스크립트가 있고 파일의 일부 내용을 바꾸는 동안 위의 두 가지 작업을 수행하려고 시도하지만(저는 다른 목적으로 이 작업을 수행합니다) 위의 두 가지 작업을 위해 특별히 추가한 섹션에서는 그렇지 않았습니다. 작업을 하고 많은 오류를 인쇄하기 시작했습니다.

perl -0pe "s#<eval>collect_model = 0</eval>#<eval>collect_model = 1</eval> s#<derta-config>.* </derta-config>##sm;   s#<function>\s*<name>DUMMY_FUNCTION.+?</function>#$file#sm" client_"$client_id".xml > "$word"_new_file.xml

그래서 나는 쉘 스크립트에서 이 작업을 수행할 수 있는지 궁금했습니다. 즉, 쉘 스크립트를 사용하여 위의 두 가지를 제거한 다음 그 출력을 세 번째 단계에서 작동하는 Perl 스크립트에 전달한다는 의미입니다. 그러면 쉘 스크립트의 출력을 아래의 Perl 스크립트에 전달할 수 있습니까? 그러면 위의 두 가지가 제거됩니다. 괜찮나요?

perl -0pe "s#<function>\s*<name>DUMMY_FUNCTION.+?</function>#$file#sm" client_"$client_id".xml > "$word"_dyn_model.xml

여기도 마찬가지 $client_id입니다 23.$wordabc

나는 이것이 효과가 있기를 원하며 가장 쉬운 것은 무엇이든 나에게 효과가 있을 것입니다. 위에서 언급한 두 가지 사항에 대한 예를 들어 보겠습니다.

답변1

XML을 구문 분석하는 데 정규식을 사용하지 마십시오. 이것은 나쁜 생각입니다. 이것이 나쁜 생각인 주된 이유는 많은 종류의 XML이 있고 의미상 동일한 일부 XML이 상당히 다른 패턴 일치를 가질 수 있다는 것입니다.

개행, 공백, 단항 태그 등을 고려하세요.

<element />
<element></element>

둘 다 동일합니다. 그런 다음 들여쓰기, 줄 바꿈, 태그 분할 등을 수행할 수 있습니다.

<element 
    att1="fish"
    att2="carrot">

또한 유효합니다.

그럼 나도 그럴게강하게"파서 사용"을 권장합니다. Perl에는 다양한 옵션이 있습니다. 제가 좋아하는 것은 다음과 같습니다 XML::Twig.

#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;

my $twig = XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( \*DATA );

foreach my $hello ( $twig->findnodes('//hello') ) {
    if ( $hello->trimmed_text =~ m/collect_model/ ) {
        $hello->set_text('collect_model = 0');
    }
}

$_->delete for $twig->findnodes('//derta-config');

$twig->print;

__DATA__
<root>
<world>
    <hello>collect_model = 1</hello>
    <hello>enable_data = 0</hello>
    <hello>session_ms = 2*60*1000</hello>
    <hello>max_collect = string_integer($extract("max_collect"))</hello>
    <hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
    <hello>output('{')</hello>
</world>
<derta-config>
    <data-users>2000</data-users>
    <test-users>2000</test-users>
    <attributes>hello world</attributes>
    <client-types>Client1</client-types>
    <target>price.world</target>
</derta-config>
</root>

왜냐하면 당신은 Perl에서 다음 줄을 좋아하는 것 같기 때문입니다:

perl -MXML::Twig -0777 -e 'my $twig = XML::Twig->parse (<>); $_->set_text("collect_model = 0") for grep { $_->text =~ m/collect_model/ } $twig->findnodes("//hello"); $_->delete for $twig->findnodes("//derta-config"); $twig -> print;'

답변2

다음을 예제 입력 파일로 사용하십시오.

$ cat client_23.xml 
<world>
    <hello>collect_model = 1</hello>
    <hello>enable_data = 0</hello>
    <hello>session_ms = 2*60*1000</hello>
    <hello>max_collect = string_integer($extract("max_collect"))</hello>
    <hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
    <hello>output('{')</hello>
</world>
<derta-config>
    <data-users>2000</data-users>
    <test-users>2000</test-users>
    <attributes>hello world</attributes>
    <client-types>Client1</model-types>
    <target>price.world</target>
</derta-config>

다음을 사용하여 두 가지 변경을 수행할 수 있습니다.

$ sed 's|<hello>collect_model = 1</hello>|<hello>collect_model = 0</hello>|; \|<derta-config>|,\|</derta-config>|d' client_23.xml 
<world>
    <hello>collect_model = 0</hello>
    <hello>enable_data = 0</hello>
    <hello>session_ms = 2*60*1000</hello>
    <hello>max_collect = string_integer($extract("max_collect"))</hello>
    <hello>max_collect = parenting(max_collect, max_collect, 1.0e99)</hello>
    <hello>output('{')</hello>
</world>

어떻게 작동하나요?

두 개의 sed 명령이 있습니다. 첫 번째는 교체이고, 두 번째는 삭제입니다.

  • s|<hello>collect_model = 1</hello>|<hello>collect_model = 0</hello>|

    대체 명령의 형식은 입니다 s|old|new|. 따라서 이것이 old원본 <hello>collect_model = 1</hello>이고 new이것이 대체입니다 <hello>collect_model = 0</hello>.

  • \|<derta-config>|,\|</derta-config>|d

    이는 일련의 행을 정의합니다. 시작 줄에는 가 포함되고 derta-config>, 끝 줄에는 가 포함됩니다 </derta-config>. 이 범위 내의 모든 행은 삭제 명령에 의해 삭제됩니다 d.

관련 정보