Perl如何从XML文件中删除标签?

问题描述 投票:0回答:1

我有一个XML文件,如下图所示,我想从我的输出中删除hashref,Perldata,以及项目键值。我主要关注的是这个。

我有很多XML文件,如下图所示,其中有很多不同的变量,我想用一段代码来自动去除不必要的标签,而不需要在Perl代码中引入每个标签。

输入内容

<perldata>
 <hashref memory_address="0xa7ab680">
  <item key="employee">
   <arrayref memory_address="0xa7dc1a8">
    <item key="0">
     <hashref memory_address="0xa7ab584">
      <item key="age">
       <hashref memory_address="0xa7ab338">
        <item key="dob">10-02-2000</item>
       </hashref>
      </item>
      <item key="department">
       <hashref memory_address="0xa7ab1d0">
        <item key="departmentname">Operations</item>
        <item key="title">Manager</item>
       </hashref>
      </item>
      <item key="location">
       <hashref memory_address="0xa7ab068">
        <item key="town">
         <hashref memory_address="0xa7aaffc">
          <item key="county">East</item>
          <item key="name">Auchinleck</item>
         </hashref>
        </item>
       </hashref>
      </item>
      <item key="name">
       <hashref memory_address="0xa7ab518">
        <item key="forename">John</item>
        <item key="surname">Down</item>
       </hashref>
      </item>
      <item key="************">M</item>
     </hashref>
    </item>
    <item key="1">
     <hashref memory_address="0xa7aae64">
      <item key="age">
       <hashref memory_address="0xa7aac90">
        <item key="dob">05-03-2000</item>
       </hashref>
      </item>
      <item key="department">
       <hashref memory_address="0xa78c490">
        <item key="departmentname">Internet</item>
        <item key="title">Watcher</item>
       </hashref>
      </item>
      <item key="location">
       <hashref memory_address="0xa798da4">
        <item key="town">
         <hashref memory_address="0xa798d38">
          <item key="county">South</item>
          <item key="name">BB</item>
         </hashref>
        </item>
       </hashref>
      </item>
      <item key="name">
       <hashref memory_address="0xa7aadf8">
        <item key="forename">Cr</item>
        <item key="surname">Moral</item>
       </hashref>
      </item>
      <item key="************">M</item>
     </hashref>
    </item>
   </arrayref>
  </item>
 </hashref>
</perldata>

我的首选输出是。

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <employee>
    <value name="************">M</value>
    <age>
      <dob>01-04-2000</dob>
    </age>
    <department>
      <departmentname>Operations</departmentname>
      <title>Manager</title>
    </department>
    <location>
      <town>
        <county>Somewhere</county>
        <name>Someplace</name>
      </town>
    </location>
    <name>
      <forename>John</forename>
      <surname>Down</surname>
    </name>
  </employee>
  <employee>
    <value name="************">M</value>
    <age>
      <dob>12-12-2000</dob>
    </age>
    <department>
      <departmentname>Internet</departmentname>
      <title>Researcher</title>
    </department>
    <location>
      <town>
        <county>Somewhere</county>
        <name>Othertown</name>
      </town>
    </location>
    <name>
      <forename>Jane</forename>
      <surname>Doe</surname>
    </name>
  </employee>
</data>

更新。 OP在回答问题时加入了这段代码(因为不是答案,所以被删除)。我把它稍微重新格式化了一下。

#!/usr/bin/perl -w

use strict;
use warnings;
use Data::Dumper;
use XML::Dumper;
use TAP3::Tap3edit;
$Data::Dumper::Indent=1;
$Data::Dumper::Useqq=1;

my $dump = new XML::Dumper;
use File::Basename;

my $perl = '';
my $xml = '';
my $tap3 = TAP3::Tap3edit->new();

foreach my $file(glob 'LB*')
{
  my $files= basename($file);
  my $filename=$files.".xml\n";
  print $filename;
  $tap3->decode($files) || die $tap3->error;
  $perl = $tap3->structure;
  $dump->pl2xml($perl, $filename);
}
java regex perl hash href
1个回答
1
投票

看起来这是一个 已知问题 与模块。而鉴于这个bug是在2015年提出的,而且从2006年开始就没有新版本的模块,我猜测这个模块已经被放弃了,这个bug(连同 许多其他)是不会被修复的。

我建议寻找一个不同的XML处理模块。我喜欢 XML::LibXML (但我也听说了关于 XML::Twig).


1
投票

我想简短的回答是 "不要使用XML::Dumper",你真正的问题是 "如何将Perl转储到XML?"。

这里有一点共同的问题。在你的Perlmonks帖子中 从XML文件中删除perldata,hashref。 (嗯,一定要注意,不管在哪里都有现成的讨论),你首先要解决数据结构的问题。但是,这其实不是你的问题,你的问题是要把Perl结构输出为XML。你提出的问题与你已经有的问题不同,这个问题有时被称为 XY问题. 这就是为什么这里的好问者往往总是问一些澄清的问题。


我的第一个想法是,你有一个Perl数据结构,我猜测是一个hash ref,你可以通过它来删除或修改你不想要的东西。

$perl = $tap3->structure;

你可以通过它来删除或修改任何你不想要的东西。这将是我的第一种方法,因为我可以使用基本的Perl功能来做这件事。如果你能给我们看一下那个数据结构,我们也许能想出一些简单的办法。

say Dumper( $perl );

看起来你看到的那些东西可能来自于... ... XML::Dumper所以你是通过使用一个差劲的工具来介绍的。我是在已经写好程序后才意识到这一点的,所以我想,你是免费得到的。

另外,如果你在别的地方发过问题,大多数人都希望你在问题中注明。我有点失望,我在这上面下了一些功夫,但已经有很多人在讨论了。从XML文件中删除perldata,hashref。 上的Perlmonks。


但是,由于我以前用苹果的属性列表(傻傻地用字典和数组做说那种通用结构)做过这种XML处理,所以这里有一个小的 XML::Twig 程序。我想这能让你达到大部分的目的,但我没有仔细检查输出。你可以用Twig来调整这个程序以适应你的口味。

XML::Twig 降到你的XML结构中。你可以为每一种节点定义 "处理程序"。这个处理程序是一个子程序引用,它可以获取当前节点在 $_,Perl的主题变量。这个 perldata 处理程序很简单,因为它只是把名字改成了 data 借用 set_tag:

        perldata  => sub { $_->set_tag( 'data' )  },

这个模块一开始有点吓人,因为你可以做的事情太多了,但是一旦你习惯了,你就拥有了一个非常强大的工具。

接下来的部分就比较复杂了。你想把所有的 hashrefarrayref标签,并将其提升一个级别。

    arrayref  => \&move_up_children,
    hashref   => \&move_up_children,

这些标签会引用一个命名的子程序 move_up_children 所以我不会重复一堆代码。Twig的部分功能允许你 "剪切 "子节点并将其 "粘贴 "到其他节点中。在本例中,将子节点剪切到 hashrefarrayref 并将它们粘贴到任何包含 hashrefarrayref. 然后,删除现在空的 hashrefarrayref:

sub move_up_children {
    my $parent = $_->parent;
    for my $child ( $_->cut_children ) {
        $child->paste( $parent );
        }
    $_->delete;
    }

我不会去通过 item 处理。由于该标签有一个通用的用法,我需要测试我遇到了哪种用法。有四种情况。

  • 那... ******** 价值
  • 非数字键(所以不是现在的孩子) arrayref)而不是 employee 遗腹子 hashref)
  • 钥匙 employee 遗腹子 hashref)
  • 其他所有的东西,都是数字键(现在已经消失了的一个孩子)。arrayref)

#!perl
use v5.30;

use XML::Twig;

# just a way to get everything into one string
my $xml = do { local $/; <DATA> };

my $twig=XML::Twig->new(
  twig_handlers =>
    {
    perldata  => sub { $_->set_tag( 'data' )  },
    arrayref  => \&move_up_children,
    hashref   => \&move_up_children,
    item      => sub {
        my $parent = $_->parent;
        my $key = $_->{'att'}{'key'};
        if( $key =~ m/\A \*+ \z/x ) {
            $_->set_tag( 'value' );
            $_->del_att( 'key' );
            $_->set_att( name => $key );
            }
        elsif( $key =~ /\D/ and $key ne 'employee' ) {
            $_->set_tag( $key );
            $_->del_att( 'key' );
            }
        elsif( $key eq 'employee' ) {
            local $_ = $_;
            move_up_children();
            }
        else {
            $_->set_tag( 'employee' );
            $_->del_att( 'key' );
            }
        },
    },
    pretty_print => 'indented',  # output will be nicely formatted
    );
$twig->parse( $xml );
my $new_xml = $twig->toString;
say $new_xml;

sub move_up_children {
    my $parent = $_->parent;
    for my $child ( $_->cut_children ) {
        $child->paste( $parent );
        }
    $_->delete;
    }

__DATA__
<perldata>
 <hashref memory_address="0xa7ab680">
  <item key="employee">
   <arrayref memory_address="0xa7dc1a8">
    <item key="0">
     <hashref memory_address="0xa7ab584">
      <item key="age">
       <hashref memory_address="0xa7ab338">
        <item key="dob">10-02-2000</item>
       </hashref>
      </item>
      <item key="department">
       <hashref memory_address="0xa7ab1d0">
        <item key="departmentname">Operations</item>
        <item key="title">Manager</item>
       </hashref>
      </item>
      <item key="location">
       <hashref memory_address="0xa7ab068">
        <item key="town">
         <hashref memory_address="0xa7aaffc">
          <item key="county">East</item>
          <item key="name">Auchinleck</item>
         </hashref>
        </item>
       </hashref>
      </item>
      <item key="name">
       <hashref memory_address="0xa7ab518">
        <item key="forename">John</item>
        <item key="surname">Down</item>
       </hashref>
      </item>
      <item key="************">M</item>
     </hashref>
    </item>
    <item key="1">
     <hashref memory_address="0xa7aae64">
      <item key="age">
       <hashref memory_address="0xa7aac90">
        <item key="dob">05-03-2000</item>
       </hashref>
      </item>
      <item key="department">
       <hashref memory_address="0xa78c490">
        <item key="departmentname">Internet</item>
        <item key="title">Watcher</item>
       </hashref>
      </item>
      <item key="location">
       <hashref memory_address="0xa798da4">
        <item key="town">
         <hashref memory_address="0xa798d38">
          <item key="county">South</item>
          <item key="name">BB</item>
         </hashref>
        </item>
       </hashref>
      </item>
      <item key="name">
       <hashref memory_address="0xa7aadf8">
        <item key="forename">Cr</item>
        <item key="surname">Moral</item>
       </hashref>
      </item>
      <item key="************">M</item>
     </hashref>
    </item>
   </arrayref>
  </item>
 </hashref>
</perldata>

输出得到的东西很接近你想要的东西,也许有一些排序问题。

<data>
  <employee>
    <value name="************">M</value>
    <name>
      <surname>Moral</surname>
      <forename>Cr</forename>
    </name>
    <location>
      <town>
        <name>BB</name>
        <county>South</county>
      </town>
    </location>
    <department>
      <title>Watcher</title>
      <departmentname>Internet</departmentname>
    </department>
    <age>
      <dob>05-03-2000</dob>
    </age>
  </employee>
  <employee>
    <value name="************">M</value>
    <name>
      <surname>Down</surname>
      <forename>John</forename>
    </name>
    <location>
      <town>
        <name>Auchinleck</name>
        <county>East</county>
      </town>
    </location>
    <department>
      <title>Manager</title>
      <departmentname>Operations</departmentname>
    </department>
    <age>
      <dob>10-02-2000</dob>
    </age>
  </employee>
</data>
© www.soinside.com 2019 - 2024. All rights reserved.