【问题标题】:Extract data between tags from files从文件中提取标签之间的数据
【发布时间】:2013-06-28 10:30:52
【问题描述】:

尝试使用 Perl 提取标签之间的数据。不幸的是,解析器在这里不是一个选项,因为:

  1. 我需要有标准代码才能针对目录中的许多文件运行。
  2. 我需要提取的内容在不同的文件中是不同的。例如:“纳入标准”在一个文件中的 <P> 中,在另一个文件中的 <L> 中,在第三个文件中的 <TD> 中。

所以,我真的别无选择,只能使用一种非常笨拙的方式来使用正则表达式来解析文件并提取数据。除非有人有更好的主意...

也就是说,我有以下代码可以在文件中进行搜索和提取。

对于给定的短语,我需要提取它下面的内容,可以是段落或列表<L>

这就是我正在做的:

  • 打开文件
  • 查找包含短语的行。
  • 检查下一行是否以<L> 标记开头,提取<L></LI> 标记之间的所有内容(行范围)。

以下是我的部分代码。这不会返回任何东西。所以,在这里寻求帮助。

  1. 我是否在正确的轨道上?
  2. 如何提取<L></L> 标签之间的全部数据并将其存储在数组中以进行计数?

代码片段:

 if (($curr_line =~ m/\binclusion criteria\b/i)
  && ($curr_line !~ m/\b....\b/)  && ($curr_line !~   /^<Bookmark/) )
 {
    $nextline = <$CURR_FILE>
  if ($next_line =~ /^<L/)
    {
        print "next line is a list\n";
        ## inclusion is a list..so extract everything from the list
        my $start = "<LI>";
        my $end = "</L>";           
        while ($next_line =~ m{($start.*?$end)}gx)
        {
            print "List is...$next_line";

        }           

    }#inner if
     }

编辑:添加输入 XML sn-p。

这是从 PDF 生成的 XML 文件之一。

我需要提取:“这是学习目的内容”。如果只有路径在所有文档中保持一致,那将很容易。它位于://Sect//H4 下,但在其他情况下位于 //Sect//H2//Sect//H1 下。这里没有一致性。

还需要提取包含和排除条件下的所有列出的内容。同样的问题。跨文档的路径不一致。

书签链接指向内容不相关的段落。

有了这种不一致的 XML,如果我仍然可以使用 1 个解析器程序从数千个文档中提取信息,那就没有比这更好的了。我使用一个糟糕的、笨拙且效率极低的搜索和提取程序的唯一原因是因为 XML 文档中的不一致。

<?xml version="1.0" encoding="UTF-8" ?>                                                            
<TaggedPDF-doc>  
  <bookmark-tree>
    <bookmark title="5.1.1 Inclusion criteria">
      <destination structID="LinkTarget_1130"/>
    </bookmark>
    <bookmark title="5.1.2 Exclusion criteria">
      <destination structID="LinkTarget_1131"/>
    </bookmark>
  </bookmark>
  <Part>
    <Sect>
      <Sect>
        <H4>2.1 Study purpose </H4>
        <P>This is study purpose content</P>
      </Sect>
      <P id="LinkTarget_1130"> This is some unrelated paragraph </P>
      <P>5.1.1 Inclusion criteria </P>
      <L>
        <LI>
          <LI_Label>1.  </LI_Label>
          <LI_Title>Title 1</LI_Title>
        </LI>
        <LI>
          <LI_Label>2.  </LI_Label>
          <LI_Title>Title 2 </LI_Title>
        </LI>
      </L>
      <P>some content 1</P>
      <P>some content 2</P>
      <P>some content 3 </P>
      <P>some content 4</P>
      <P>some content 5</P>
      <L>
        <LI>
          <LI_Label>4.</LI_Label>
          <LI_Title>Title 4</LI_Title>
        </LI>
        <LI>
          <LI_Label>5.  </LI_Label>
          <LI_Title>Title 5
        </LI>
      </L>
      <P id="LinkTarget_1131"> This is some unrelated paragraph </P>
      <P>5.1.2 Exclusion criteria </P>
      <P>Some content 1</P>
      <L>
        <LI>
          <LI_Label>1.  </LI_Label>
          <LI_Title>Title 1</LI_Title>
        </LI>
        <L>
          <LI>
            <LI_Label>2.    </LI_Label>
            <LI_Title>Title 2</LI_Title>
          </LI>
          <LI>(3) some content</LI>
        </L>
        <P>Some content </P>
      </Sect>
    </Sect>
  </Part>
</TaggedPDF-doc>

【问题讨论】:

  • 所以,与其使用真正的解析器,您宁愿破解一些东西因为这将是标准的?
  • 请展示每个 XML 文件的简短示例。这可以用解析器来完成。
  • 解析器在这里不是一个选项,解析器是一个解决方案。
  • 你的输入是什么样的?这将帮助我们确定解析文件的最佳方式。很可能,某种解析器会比正则表达式更好地工作。解析器可以将您的数据放入可以轻松遍历的结构中。如果某些数据与您的布局期望不完全匹配,正则表达式将失败。更糟糕的是,该程序会为你的测试工作,但当你的工作上线时就会失败。
  • 感谢您的回复。用示例 xml 更新了我的原始帖子。

标签: xml perl


【解决方案1】:

错了。如果不使用适当的 XML 解析器,您永远不应该阅读 XML,而且您的 XML 复杂且多变的事实更加强化了这种情况。

很明显,如果数据根本没有模式,那么无论您使用哪种编程语言,您都无法提取任何有用的东西。但你必须认为它有某种模式,否则你不会尝试这项任务。所以你需要告诉我们那个模式是什么。例如,如果您想要在名称以“H”开头的第一个元素之后的第一个后续元素,那将是

//*[starts-with(name(), 'H')][1]/following-sibling::*[1]

不管规则如何,如果你能用英语表达,那么你就可以用 XPath 表达(或者如果事情变得非常棘手,用 XSLT 或 XQuery)。

坦率地说,我认为您在这里遇到的困难在于,当您没有考虑要实施哪些规则时,您正在尝试用代码破解它。这在任何编程语言中都注定会失败。

【讨论】:

    【解决方案2】:

    您的要求有点矛盾,但我相信像

    这样的 XPATH 表达式
    (//Sect//H1 | //Sect//H2 | //Sect//H3 | //Sect//H4)[1]/following-sibling::*
    

    可以做你想做的事。当在“XML”的清理版本上运行时,例如

    use strict; use warnings; use 5.010; use XML::LibXML;
    
    my $dom = XML::LibXML->load_xml(IO => \*DATA); # XML is in DATA file handle
    
    say $dom->findvalue('(//Sect//H1 | //Sect//H2 | //Sect//H3 | //Sect//H4)[1]/following-sibling::*');
    

    输出

    This is study purpose content
    

    【讨论】:

    • 这适用于这个特定的值。但是如果我想动态提取: 5.1.1 包含标准和它下面的所有子项,我怎么知道在哪里停止?我只需要检索

      5.1.1 纳入标准

      5.1.2 纳入标准

      之间的所有内容
    • @simak 然后你应该发布更多示例(删除不必要的行)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-26
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    • 2021-05-17
    相关资源
    最近更新 更多