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

1 xml awk grep parsing sed

试图找出最好的方法(使用我在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>
Run Code Online (Sandbox Code Playgroud)

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

干杯,

粘土

Tod*_*obs 6

使用XPath提取文章

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

xgrep -x "//article[@id]" /tmp/foo
Run Code Online (Sandbox Code Playgroud)

这可能就是您所需要的.但是,它不会分开文章; 它比使用正则表达式更可靠地提取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'
Run Code Online (Sandbox Code Playgroud)

显然,您可以使用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
Run Code Online (Sandbox Code Playgroud)