【问题标题】:how to check xml file line by line with perl script如何使用perl脚本逐行检查xml文件
【发布时间】:2020-05-01 12:25:11
【问题描述】:

我想比较这两个文件,一个是用户的输入文件 txt 文件,另一个文件是 xml 文件的配置文件。如果用户的输入文件值与配置文件匹配,则显示匹配的函数。

这是用户的输入文件

L84A:FIP:70:155:15:18:
L83A:55FIP:70:155:15:

上述文件中:L84A为Design_ID,FIP为Process_ID,70到18为register_ID。

这是配置文件

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Sigma>
        <Run>
                <DESIGN_ID>L83A</DESIGN_ID>
                <PROCESS_ID>55FIP</PROCESS_ID>
                <RegisterList>
                        <Register>70</Register>
                        <Register>155</Register>
                </RegisterList>
        </Run>
        <Run>
                <DESIGN_ID>L83A</DESIGN_ID>
                <PROCESS_ID>FRP</PROCESS_ID>
                <RegisterList>
                        <Register>141</Register>
                        <Register>149</Register>
                        <Register>151</Register>
                </RegisterList>
        </Run>
        <Run>
                <DESIGN_ID>L84A</DESIGN_ID>
                <PROCESS_ID>55FIP</PROCESS_ID>
                <RegisterList>
                        <Register>70</Register>
                        <Register>155</Register>
                </RegisterList>
        </Run>
</Sigma>

所以在这种情况下输出应该显示:

L84A: doesn't has FIP process ID in config file.
L83A:
  55FIP
   70 - existing register ID
   155 - existing register ID
   15 - no existing register ID.

我的代码不检查各自的进程 ID 和注册 ID。它如下所示。

L84A
 FIP
  70 - existing register ID
  155 - existing register ID
  15 - existing register ID
  18 - no existing register ID
L83A
 55FIP
  70 - existing register ID
  155 - existing register ID
  15 - existing register ID

下面是我的代码:

use strict; 
use warnings;
use vars qw($file1 $file1cnt @output);
use XML::Simple;
use Data::Dumper;
# create object
my $xml = new XML::Simple;

# read XML file
my $data = $xml->XMLin("sigma_loader.xml");
my $file1 = "userinput.txt";

readFileinString($file1, \$file1cnt); 

while($file1cnt=~m/^((\w){4})\:([^\n]+)$/mig)
{  
  my $DID = $1;
  my $reqconfig = $3;
  while($reqconfig=~m/^((\w){5})\:([^\n]+)$/mig) #Each line from user request
  {  
    my $example1 = $1; #check for FPP/QBPP process
    my $example2 = $3; #display bin full lists.

   if(Dumper($data) =~ $DID)
   {
     print"$DID\n";
     if(Dumper($data) =~ $example1)
     {
       print"$example1\n";
       my @second_values = split /\:/, $example2;
       foreach my $sngletter(@second_values)
        { 

          if( Dumper($data) =~ $sngletter)
          {
            print"$sngletter - existing register ID\n";
          }
          else
          {
            print"$sngletter - no existing register ID\n";
          }
        }
     }
     else
     {
      print"$DID doesn't has $example1 process ID in config file\n";
     }
   }
   else
   {
    print"new Design ID deteced\n";
   } 
 }
 while($reqconfig=~m/^((\w){3})\:([^\n]+)$/mig) #Each line from user request
 {  
    my $example1 = $1; #check for FPP/QBPP process
    my $example2 = $3; #display bin full lists.

   if(Dumper($data) =~ $DID)
   {
     print"$DID\n";
     if(Dumper($data) =~ $example1)
     {
       print"$example1\n";
       my @second_values = split /\:/, $example2;
       foreach my $sngletter(@second_values)
        { 

          if( Dumper($data) =~ $sngletter)
          {
            print"$sngletter - existing register ID\n";
          }
          else
          {
            print"$sngletter - no existing register ID\n";
          }
        }
     }
     else
     {
      print"$DID doesn't has $example1 process ID in config file\n";
     }
   }
   else
   {
    print"new Design ID deteced\n";
   } 
 }
}

sub readFileinString
#------------------>
{
    my $File = shift;
    my $string = shift;
    use File::Basename;
    my $filenames = basename($File);
    open(FILE1, "<$File") or die "\nFailed Reading File: [$File]\n\tReason: $!";
    read(FILE1, $$string, -s $File, 0);
    close(FILE1);
} 

【问题讨论】:

  • 输入文件在这里如何显示L84A:FIP:70:155:15:18: L83A:55FIP:70:155:15:这是逐行或完全合并的内容...?
  • 它将逐行显示
  • 你为什么要一行一行地做那件事?对 XML 文件使用 XML 解析器会容易得多。 XML::Simple 并不是真正的一种。但我们可能可以使用它。 // 你的代码也有一些质量问题,其中一些是安全问题。

标签: perl


【解决方案1】:

您的代码中有几处没有真正意义,例如使用 Data::Dumper 并使用正则表达式解析输出。我不会审查您的代码,因为这与 Stack Overflow 无关,而是会为您提供一个替代解决方案并引导您完成它。

请注意 XML::Simple 不是一个很好的工具。不鼓励使用它,因为它在处理某些情况下非常糟糕。但是对于您非常简单的 XML 结构,它可以工作,所以我保留了它。

use strict;
use warnings;
use XML::Simple;
use feature 'say';

# read XML file and reorganise it for easier use
my $data;
foreach my $run (@{XMLin(\*DATA)->{Run}}) {
    $data->{$run->{DESIGN_ID}}->{$run->{PROCESS_ID}} =
      {map { $_ => 1 } @{$run->{RegisterList}->{Register}}};
}

# read the text file - I've skipped the read
my @user_input = qw(
  L84A:FIP:70:155:15:18:
  L83A:55FIP:70:155:15:
);

foreach my $line (@user_input) {
    chomp $line
      ; # we don't need this in my example, but you do when you read from a file
    my ($design_id, $process_id, @register_ids) = split /:/, $line;

    # extra error checking just in case
    if (not exists $data->{$design_id}) {
        say "$design_id does't exist in data";
        next;
    }
    if (not exists $data->{$design_id}->{$process_id}) {
        say "$design_id: doesn't have $process_id";
        next;
    }

    say "$design_id:";
    say " $process_id";
    foreach my $register_id (@register_ids) {
        if (exists $data->{$design_id}->{$process_id}->{$register_id}) {
            say "  $register_id - existing register ID";
        }
        else {
            say "  $register_id - no existing register ID";
        }
    }
}


__DATA__
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Sigma>
        <Run>
                <DESIGN_ID>L83A</DESIGN_ID>
                <PROCESS_ID>55FIP</PROCESS_ID>
                <RegisterList>
                        <Register>70</Register>
                        <Register>155</Register>
                </RegisterList>
        </Run>
        <Run>
                <DESIGN_ID>L83A</DESIGN_ID>
                <PROCESS_ID>FRP</PROCESS_ID>
                <RegisterList>
                        <Register>141</Register>
                        <Register>149</Register>
                        <Register>151</Register>
                </RegisterList>
        </Run>
        <Run>
                <DESIGN_ID>L84A</DESIGN_ID>
                <PROCESS_ID>55FIP</PROCESS_ID>
                <RegisterList>
                        <Register>70</Register>
                        <Register>155</Register>
                </RegisterList>
        </Run>
</Sigma>

我做了一些假设。

  1. 您已经知道如何读取文本文件,因此我将其逐行放入数组中。但是,您的文件读取代码存在一些问题,您应该使用三参数打开和词法文件句柄。您对open 的调用应如下所示:

    open my $fh, '<', $filename or die "$!: error...";
    

    或者,考虑使用Path::Tiny

  2. 我正在从__DATA__ 部分获取 XML 文件。这就像一个文件句柄。

让我们看看我的代码。

当我们读取 XML 结构时,它看起来像这样直接来自 XMLin

\ {
    Run   [
        [0] {
            DESIGN_ID      "L83A",
            PROCESS_ID     "55FIP",
            RegisterList   {
                Register   [
                    [0] 70,
                    [1] 155
                ]
            }
        },
        [1] {
            DESIGN_ID      "L83A",
            PROCESS_ID     "FRP",
            RegisterList   {
                Register   [
                    [0] 141,
                    [1] 149,
                    [2] 151
                ]
            }
        },
        [2] {
            DESIGN_ID      "L84A",
            PROCESS_ID     "55FIP",
            RegisterList   {
                Register   [
                    [0] 70,
                    [1] 155
                ]
            }
        }
    ]
}

这对于我们计划做的事情不是很有用,所以我们必须重新安排它。我想稍后在哈希引用上使用exists,以便在我们正在查看的 ID 匹配时更容易查找。这称为查找哈希。我们可以将-&gt;{Run} 键作为XML::Simple 将所有&lt;Run&gt; 元素组合到一个数组引用中,而&lt;Sigma&gt; 标记只是被跳过,因为它是根元素。

每个设计ID可以有多个进程,所以我们将这两个分层组织,并放入另一个查找哈希,其中每个寄存器都是一个键,我们只是使用1作为键。密钥无关紧要。

这给了我们不同的数据结构:

\ {
    L83A   {
        55FIP   {
            70    1,
            155   1
        },
        FRP     {
            141   1,
            149   1,
            151   1
        }
    },
    L84A   {
        55FIP   {
            70    1,
            155   1
        }
    }
}

这在以后更容易理解和使用。

现在我们解析用户输入,并遍历每一行。格式似乎很清楚。它有点像 CSV 文件,但使用冒号:,所以我们可以split。这给了我们两个 ID,后面的所有值都是寄存器,所以我们把它们放在一个数组中。

您的示例没有设计 ID 在 XML 文件中不存在的情况,但鉴于这是基于用户输入的,我们还是应该检查一下。在现实世界中,数据总是很脏的。

然后我们可以检查数据中$design_id 中的$process_id exists 是否存在。如果没有,我们告诉用户并跳到next 行。

然后我们必须迭代所有的注册 ID。 $register_id 要么存在于我们的第二个查找哈希中,要么不存在。

这为我们提供了您期望的确切输出。

L84A: doesn't have FIP
L83A:
 55FIP
  70 - existing register ID
  155 - existing register ID
  15 - no existing register ID

这段代码更短,更容易阅读,运行速度更快。我使用Data::Printer 来显示数据结构。

【讨论】:

  • 感谢您的详细解释
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多