【问题标题】:XML::Twig parsing same name tag in same pathXML::Twig 解析相同路径中的相同名称标签
【发布时间】:2016-12-28 11:55:25
【问题描述】:

我正在尝试帮助一位对 EMR(电子病历)系统不满意并想更换但公司表示他们无法从数据库中提取患者人口统计数据的客户(我们询问他们是否可以得到我们csv 文件中的姓名、地址、出生日期(某种非常基本的东西)——但他们声称他们做不到。 (考虑到他们正在使用 sql 数据库,这很疯狂)。 无论如何-他们移交患者的方式是在 xml 文件中,其中大约有 40,000 多个。但它们包含的不仅仅是人口统计数据。 在做了一些研究并在 15 年前完成了广泛的 Perl 编程之后(我承认这些年来它已经生锈了)——我认为这应该是在 Perl 中完成的一项好任务——我遇到了 XML::Twig 模块,它似乎能够做到这一点。 不幸的是,感兴趣的 xml 代码如下所示:

<patient extension="Patient ID Number">  // <--Patient ID is 5 digit number)
  <name>
    <family>Patient Family name</family>
     <given>Patient First/Given name</given>
     <given>Patient Middle Initial</given>
  </name>
  <birthTime value=YEARMMDD"/>

xml 文件中有更多地址等字段。

这是我的代码:

my $twig=XML::Twig->new( twig_handlers => {
  'patient/name/family'      => \&get_family_name,
  'patient/name/given'       => \&get_given_name
});
$twig->parsefile('test.xml');

my @fields;

sub get_family_name {my($twig,$data)=@_;$fields[0]=$data->text;$twig->purge;}
sub get_given_name {my($twig,$data)=@_;$fields[1]=$data->text;$twig->purge;}

我可以毫无问题地读取所有具有唯一标签(家庭、城市、邮政编码等)的信息,但 XML:Twig 只返回标签的中间首字母。 例如,如何解决第一次出现的“given”并将其分配给 $fields[1] 并将第二次出现的“given”分配给 $fields[2] - 或者取消中间的首字母。

另外,我如何使用 XML::Twig 提取“Patient ID”或“birthTime”值 - 我找不到对它的引用。 我尝试使用 $data->findvalue('birthTime') 但结果为空。

我查看了:Perl, XML::Twig, how to reading field with the same tag,这非常有帮助,但由于重复的标签位于同一路径中,所以它是不同的,我似乎无法找到答案。 XML::Twig 是否只返回在解析文件时找到匹配项时找到的最后一个值?有没有办法提取所有出现的值?

提前感谢您的帮助!

【问题讨论】:

    标签: perl xml-parsing xml-twig


    【解决方案1】:

    从文档中很容易假设您应该对所有事情都使用回调。但是解析整个文档并对其进行整体查询同样有效,尤其是在数据量很小的情况下

    从您的问题中不清楚每个患者是否都有一个单独的 XML 文件,并且您没有显示 patient 元素包含的内容,但我建议您使用折衷方法并仅为 @ 编写处理程序987654323@ 提取所有所需信息的元素

    我选择从每个patient 元素中构建一个信息哈希%patient,并将其推送到包含文件中所有数据的数组@patients 上。如果每个文件只有一名患者,则需要更改此设置

    我已经解决了name/given 元素的问题,方法是获取所有元素并将它们连接成一个带有中间空格的字符串。希望合适

    这是完全未经测试的,因为我目前手头只有一台平板电脑,所以要小心。它确实有编译的机会,但如果它没有错误,我会感到惊讶

    use strict;
    use warnings 'all';
    
    use XML::Twig;
    
    my @patients;
    
    my $twig = XML::Twig->new(
        twig_handlers => { patient => \&get_patient }
    );
    $twig->parsefile('test.xml');
    
    sub get_patient {
        my ($twig, $pat) = @_;
    
        my %patient;
    
        $patient{id} = $pat>att('extension');
    
        my $name         = $pat->first_child('name');yy
        $patient{family} = $name->first_child_trimmed_text('family');
        $patient{given}  = join ' ', $name->children_trimmed_text('given');
    
        $patient{dob}    = $pat->first_child('birthTime')->att('value');
    
        push @patients, \%patient;
    }
    

    【讨论】:

    • 您好,感谢您的快速回复,我今晚会尝试。但是对于您的问题 - 每个患者都有自己的 xml 文件 - 我们有大约 40,000 多个我需要解析。是的,我忘记了最后一行中患者的结束-在确定问题框中的格式时遇到了一些麻烦-然后忘记在最后添加它(因为复制和粘贴在文本框中不起作用代码似乎)。
    • 您好 Borodin,非常感谢您的帮助 - 您发布的内容帮助我更好地理解了 Twig 模块,并且我能够解析我需要的数据。不,我可以清理数据并通过这些文件运行它。谢谢!
    • 最后还有一个问题——我喜欢将散列推入全局数组——非常整洁。我的问题是 - 如果我必须解析 40'000 个文件,这会是一个问题吗?该数组中有 40'000 多个散列? perl 可以处理如此大的数组 - 还是将每个文件解析的结果直接写入 csv 文件会更好?我想我问的是小文件操作是否比用 40'000 个哈希填充数组并在最后将它们写入 csv 文件更占用资源?谢谢! :)
    • @yoeddy:我很乐意提供帮助,但我不清楚您的数据的性质,如果我知道每个文件都包含一个人的数据,我会写一些完全不同的东西。如果您需要做的只是创建一个 CSV(您应该为此使用 Text::CSV),那么我将为每个输入 XML 文件编写一行输出,而完全忘记哈希数组。这是 XML 文件的全部内容,还是有更多数据? patient 是根元素,还是有更多包含它的标记?
    • 别担心,我应该更清楚。但我实际上很高兴,因为我喜欢那个解决方案,即使我会研究 Text::CSV 模块。患者元素周围还有许多其他标记 - 但我能够仅隔离我需要的患者数据而忽略其余数据。但正是您的示例代码帮助我弄清楚了 TWIG 是如何工作的,帮助和示例有点通用,我不知道如何将它应用于交给我们的奇怪的 xml 文件。所以谢谢你,这是一个很大的帮助。如果我需要对 text::CSV 模块稍加推动,我会告诉你。 ;-)
    猜你喜欢
    • 1970-01-01
    • 2015-09-25
    • 2023-03-06
    • 2014-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-11
    相关资源
    最近更新 更多