【问题标题】:Comparing strings from XML in Perl?在 Perl 中比较 XML 中的字符串?
【发布时间】:2015-10-06 06:05:40
【问题描述】:

完全免责声明:我是 Perl 的新手,一周或更短的经验。在工作中,我目前的项目涉及一个过程,在该过程中,我们从各个机构获取表示课程目录的 XML 文件,并将它们连接到一个文件中。我有一个可以正常工作的 Perl 脚本 + 模块,可以做到这一点;但是,我希望通过检查合并的文件是否满足以下条件来添加一些额外的功能:

1) 每个班级列表都来自同一学期(包含在标签中)

2) 每个班级都来自同一年(这包含在标签中)

这是我当前在合并后运行的子程序(这意味着问题肯定在下面的代码中):

sub check_files {
    my ($self, $file) = @_;
    my $parser;
    my $parsed;
    my @semesters;
    my @years;
    my $answer = 0;
    my $correct = 0;

    $parser = XML::LibXML->new;
    $parsed = $parser->parse_file($file);

    @semesters = $parsed->getElementsByTagName("SEMESTER");
    @years = $parsed->getElementsByTagName("YEAR");

    foreach my $semester1 (@semesters) {        
        my $semester2 = $semesters[1];

        if($semester1 ne $semester2) {
            if($semester1 ne "<SEMESTER>Do not delete this row</SEMESTER>") {
                print "Check semesters in data! $semester1 $semester2 \n\n";
                $answer += 1;
            }
        } else {
            print "Equal strings: $semester1 $semester2 \n\n";
            $correct += 1;
        }
    }

    foreach my $year1 (@years) {
        my $year2 = $years[1];

        if($year1 ne $year2) {
            if($year1 ne "<YEAR>Do not delete this row</YEAR>") {
                print "Check years in data! $year1 $year2 \n\n";
                $answer += 1;
            }           
        } else {
            print "Equal strings: $year1 $year2 \n\n";
            $correct += 1;
        }
    }

    print "Errors: $answer Correct: $correct \n\n";
    return $answer;

}

我根据元素 1 而不是 0 检查所有内容,因为连接的第一个文件是标题行(应该等于“不要删除此行”的内容)。因此,“不要删除”的东西应该总是元素 0。

我在控制台中收到很多“检查数据中的学期!2013 2013”​​行。事实上,我的 $correct 变量增加的唯一时间是当条件失败时标题行。这让我觉得字符串比较有点搞砸了;我能想到的唯一解释是指针问题和编码。但同样,我上周才开始使用 Perl,所以我真的不知道我在说什么。我知道我的代码也不优雅,对此我深表歉意。

感谢任何可以提供帮助的人,或者甚至阅读本文并决定不提供帮助的人。

【问题讨论】:

  • 布局合理的代码;谢谢。这个my $semester2 = $semesters[1] 很可疑。您正在将@semesters 的每个元素与其第二个元素进行比较。如果这确实是您的意图,那么该语句应该在for 之前,或者更确切地说,您应该遍历@semesterslast if $i == 1索引。此外,您不得将您的元素与示例再现进行比较。您的 XML 数据可能以非常不同的方式表示相同的数据。您能否提供您的 XML 数据的副本或示例?没有看到输入很难提供解决方案
  • 如果您的数据太大而无法发布,请考虑将其上传到pastebin 之类的网站,或者在此处放置一些可以证明您描述的问题的内容
  • XML 格式如下:&lt;SECTION&gt; ... &lt;YEAR&gt;Do not delete this row&lt;/YEAR&gt; &lt;SEMESTER&gt;Do not delete this row&lt;/SEMESTER&gt; ... &lt;/SECTION&gt; &lt;SECTION&gt; ... &lt;YEAR&gt;2013&lt;/YEAR&gt; &lt;SEMESTER&gt;F&lt;/SEMESTER&gt; ... &lt;/SECTION&gt; 以此类推,每个 SECTION 代表一门课程。 XML 需要很长时间才能粘贴到 Pastebin 中,但如果这还不足以解决问题,我可以继续使用它。
  • 事实证明,对于 Pastebin 来说,数据实际上太大了。不过,除了我在上面发布的数以千计的内容之外,它的内容并不多。
  • 我应该补充一点,我检查第二个元素,因为那是“不要删除”行之后的元素。从理论上讲,它应该等于其他一切或不等于其他一切。

标签: xml string perl comparison


【解决方案1】:

当我针对您显示的数据运行您的代码时,我没有得到您描述的输出,但我确实为您提供了解决方案

您确实需要了解 XML 数据。它的嵌套非常像函数式编程语言,所以标签必须是平衡的,并且总是有一个单一的根节点。在你的数据中它被称为&lt;ROOT&gt;,如果你在文件的末尾看一下,就会有一个结束&lt;/ROOT&gt;

此代码通过使用 XPath 表达式查找除第一个 SECTION 元素之外的所有元素,然后从每个元素中提取 YEARSEMESTER 子元素的值,并在几个哈希

如果找到多年或多个学期,我不知道您希望您的子例程做什么,所以这一切只是打印几行摘要行。我希望你能理解如何从这里继续下去

sub check_files2 {
    my $self = shift;
    my ($file) = @_;

    my $doc = XML::LibXML->load_xml(location => $file);

    my @sections = $doc->findnodes('/ROOT/SECTION[position() > 1]');
    printf "%d sections found after the first\n", scalar @sections;

    my (%years, %semesters);

    for my $section ( @sections ) {
        my $year = $section->findvalue('YEAR');
        my $semester = $section->findvalue('SEMESTER');
        ++$semesters{$semester};
        ++$years{$year};
    }

    my @years = keys %years;
    printf "%d different years: %s\n", scalar @years, "@years";

    my @semesters = keys %semesters;
    printf "%d different semesters: %s\n", scalar @semesters, "@semesters";
}

输出

24 sections found after the first
1 different years: 2013
1 different semesters: F

【讨论】:

  • 非常感谢!看起来这段代码做了我想做的事情,除了更好地利用那些 LibXML 函数(findnodes 和 findvalue 正是我应该使用的)。我知道 XML 的结构,这就是为什么我认为每学期和每年只抓取一次是可行的,因为它们每个部分只出现一次——不过,这是一个结构更好的解决方案。
  • @jah:我很乐意提供帮助。我假设您不了解 XML 结构,因为您无法创建格式正确的实时数据子集。不用担心
  • @jah:您还应该学会在第一次定义 Perl 变量时(当它们获得值时)声明它们,而不是在块或文件顶部的列表中声明它们。它有助于use strict 帮助您并使您的代码更具可读性。我想你已经习惯了 C 或类似的东西
  • 我已经习惯了 Scheme 和 Java,还混入了一些 VBA。感谢您在使用变量时声明变量的提示。我认为在顶部声明所有内容更具可读性,但这当然只是一个假设。
猜你喜欢
  • 1970-01-01
  • 2015-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-13
  • 2015-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多