如何在Perl中同时解析多个文件的相同元素

时间:2010-07-22 19:54:29

标签: perl

我想在perl中合并几个xml文件。每个文件都由很多元素组成;我需要将数据与这些文件中的相同元素合并。例如

file1包含元素{e1,e2,e4}

file2包含元素{e1,e3,e4}

file3包含元素{e2,e4,e5}

所以我需要将file1的e1与file2的e1合并,合并file1的e2和file3的e2等,合并的结果将保存在另一个文件中。

由于这些文件的大小很大,因此按文件合并数据文件是不好的,即解析整个文件1,然后解析整个文件2并将其与file1合并。因为这将消耗大量内存。

所以我计划逐个元素地合并数据。即解析所有文件的e1,释放内存,然后解析所有文件的元素2,释放内存等。

目前我使用xml:parser:sax解析器来解析和处理文件。

我的问题是如何按元素实现merge元素。我不知道如何控制这些文件来处理相同的元素。使用条件信号? fork()或者......其他?任何人都可以在这里给我一个例子,因为我对这两种方式都不熟悉。 THX。

以下是合并数据的示例: 文件1:

<class name="math"&GT;

<string&GT; luke1 </string&GT;

<string&GT; luke2 </string&GT;

</class name&GT;

<class name="music"&GT;

<string&GT; mary1 </string&GT;

<string&GT; mary2 </string&GT;

</class name&GT;

file2的:

<class name="math"&GT;

<string&GT; luke1 </string&GT;

<string&GT; luke3 </string&GT;

</class name&GT;

<class name="music"&GT;

<string&GT; mary1 </string&GT;

<string&GT; mary3 </string&GT;

</class name&GT;

<class name="english"&GT;

<string&GT; TOM1 </string&GT;

<string&GT; tom2 </string&GT;

</class name&GT;

应该合并到另一个文件:

<class name="math"&GT;

<string&GT; luke1 </string&GT;

<string&GT; luke2 </string&GT;

<string&GT; luke3 </string&GT;

</class name&GT;

<class name="music"&GT;

<string&GT; mary1 </string&GT;

<string&GT; mary2 </string&GT;

<string&GT; mary3 </string&GT;

</class name&GT;

<class name="english"&GT;

<string&GT; TOM1 </string&GT;

<string&GT; tom2 </string&GT;

</class name&GT;

注意我想合并所有文件的元素数学,然后合并所有文件的元素音乐,然后合并所有文件的元素。

3 个答案:

答案 0 :(得分:2)

<强>更新

是的,您可以尝试使用SAX解析器以“并行”方式处理3个文件,如果您的回调实现“睡眠/唤醒/检查其他SAX解析器是否表示继续”机制。基本上差的线程和消息传递的近似。

只有当每个XML文件中的元素按照相同的顺序排序并且理想情况下按字母顺序排序时才会起作用 - 这样您就可以通过SAX解析器在每个文件中线性移动,并保证您同时点击相同的元素因此一次只能在内存中保存3-6个元素。它基本上将3个排序数组合并为1个排序数组。

认真地怀疑这种方法甚至会远远优于我下面列出的原始算法,但如果你想尝试实现它,那就去吧。

<强> ORIGINAL:

基本上,做你想做的最好的(如果不是唯一的)方法是建立一个需要合并的所有元素的数据库。

可能将元素name-or-id映射到N个true / false字段,每个XML文件一个;或者甚至是“已经合并”的单个是/否值 - 我将在下面的示例逻辑中使用后一个选项。

该数据库是否将实现为in-memory-hash;或者存储在文件中的绑定哈希以避免内存问题,或者正确的数据库(实现为XML,或SQLite,或DBM,或真正的数据库后端)不太重要;除了第一个选项显然会消耗内存消耗。

请注意XML数据库选项,因为您可能会将生成的XML文件用作数据库。这可能实际上是你最简单的选择,不确定 - 如果你有的话,我会亲自推荐一个绑定的哈希或真正的数据库后端。

完成后,算法很明显:

  • 使用SAX解析器循环遍历每个文件

  • 在找到的每个元素上,搜索数据库中的该元素。如果已标记为已处理,请跳过。如果没有,请将数据库添加为已处理。

  • 使用XPath在所有后续文件中查找相同的元素。例如。处理file2.xml时,只搜索file3.xml,因为file1.xml没有该元素(否则它将从file1.xml处理并已经出现在数据库中)。

  • 合并使用XPath找到的所有元素以及当前文件中的元素,并插入到生成的XML文件中并保存。

  • 结束两个循环。

请注意,这个答案并未直接解决用于实现每个步骤的模块 - 可能是XML :: Parser或任何其他用于解析的sax解析器,用于在其他文件中搜索的XML :: XPath,以及类似XML :: SAX :: Writer编写我认为的结果文件,虽然我从来没有在非DOM模型中编写文件,但我不想让te后者成为官方推荐;如果你想知道哪个模块最适合你,你可能想把它变成一个单独的问题,或者希望别人用更精确的模块推荐来回答这个问题。

答案 1 :(得分:0)

(抱歉,我无法以某种方式添加评论所以我必须在“发布你的答案”中发表我的评论)

嗨DVK,

我不明白你的意思。正如我所说,我不想逐个文件解析,即。解析file1中的所有元素,将数据记录在内存中,然后解析file2中的所有元素,将数据记录在内存中并将其与从file1获取的数据合并,然后解析file3中的所有元素....最后得到合并的数据并将其保存到结果文件中。这种方法占用了大量的内存。

所以我想处理所有文件的一个元素保存它,释放这个元素的内存,然后处理所有文件的下一个元素,保存它....

我不明白每个文件的循环是什么。所以你仍然建议使用我提到的第一种方法?什么是“在所有后续文件中查找相同的元素”,您现在要解析现在要再次使用XPATH解析每个文件的每个元素的所有文件?

答案 2 :(得分:0)

我喜欢XML :: LibXML,所以我使用XML :: LibXML :: Reader。在指定为脚本参数的每个输入文件上打开一个单独的XML :: LibXML :: Reader,然后依次调用 - &gt;读取每个输入文件,在每一轮中只输出一次输出,稍微多一点合并点的复杂逻辑。如果你有比文件描述符更多的输入文件,你将不得不批量合并它们;我会在shell脚本或Makefile中执行此操作。