使用Grep / Sed / Awk拆分XML文件?

时间:2012-07-11 19:14:25

标签: xml parsing sed awk grep

尝试找出最好的方法(使用我在Grep / Sed / Awk中所知的方法)根据它的单个字符串(键?)分割XML文件。我有一个XML文件,它是我所有当前FAQ条目的SQL转储,因此它包含一个条目ID,然后是一个相当大的HTML格式文档。我希望将这些条目分开,以便我可以轻松地将它们弹出到编辑器中并清理格式以导入到新的KB / FAQ系统。以下是我的数据示例:

 <article id="3">
  <language>en</language>
  <category>Category Name</category>
  <keywords>Keywords, by, comma</keywords>
  <question>Question?</question>
  <answer>HTML Formatting</answer>
  <author>Author</author>
  <data>2010-05-13 09:32</data>
 </article>

XML文件包含我以这种格式重新连接的每篇KB文章。我很乐意用bash来搞清楚,我只是不知道如何根据搜索将它分成多个文件。

干杯,

粘土

3 个答案:

答案 0 :(得分:6)

使用XPath提取文章

如果您的文件是有效的XML,则可以使用xgrepXMLStarlet之类的实用程序来解析文件以获取XPath表达式。例如,使用xgrep:

xgrep -x "//article[@id]" /tmp/foo

这可能就是您所需要的。然而,它不会分裂文章;它比使用正则表达式更可靠地提取XML的正确部分。

将文章节点拆分为带有管道的文件

如果您确实需要将文章拆分为单独的文件,则可以执行以下操作:

xgrep -x "//article[@id]" /tmp/foo.rb |
ruby -ne 'BEGIN { counter=0 }
          counter += 1 if /<article/
          if /<article/ ... /<\/article/
            File.open("#{counter}.xml", "a") { |f| f.puts $_ }
          end'

显然,您可以使用Ruby XML库完成所有工作,但我更喜欢将此类问题视为shell管道。您的里程可能会有所不同。

另外,请注意上面的Ruby脚本将按顺序编号您的文章而不是文章ID。如果您的XML中有重复的ID,则可能更好。

带有XmlSimple的纯Ruby

好的,好的......我不能单独留下这个。首先在上面的管道中使用外部shell实用程序似乎是一个好主意,但如果您还是要使用Perl或Ruby,那么您也可以使用XmlSimple库。

下面的Ruby脚本比管道版本稍长,但为您提供了更多的控制和灵活性。以此为出发点,考虑您的所有可能性:

#!/usr/bin/env ruby

require 'xmlsimple'

counter = 0
node_name = 'article'
xml = XmlSimple.xml_in '/tmp/foo'

xml[node_name].uniq.each do |node|
  counter = sprintf("%03d", counter.next)
  XmlSimple.xml_out(node,
                    RootName: node_name,
                    OutputFile: "/tmp/#{counter}.xml")
end

答案 1 :(得分:2)

cat file.xml | \
perl -p -i -e 'open(F, ">", ($1).".xml") if /<article id="(\d+)"/; print F;' 

将根据文章的ID分割xml文件。每个文章部分都将存储在自己的文件中,其ID号在名称中。 即使对于hige文件(sedawk等,它的工作速度也非常快,在这种情况下解决方案真的很慢。)

答案 2 :(得分:0)

这是awk的一个简单想法:

每当您点击带有文章开始标记的行时,将计数器变量递增1。然后,为每一行进行系统调用,如“echo $ 0&gt;&gt; file $ COUNTER”。这应该很容易实现