1

试图找出最好的方法(或者通过使用我在 Grep / Sed / Awk 中所知道的)来根据它的单个字符串(键?)分割一个 XML 文件。我有一个 XML 文件,它是我当前所有常见问题解答条目的 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 很满意,我只是不知道如何根据搜索将其拆分为多个文件。

干杯,

黏土

4

3 回答 3

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
于 2012-07-11T22:44:01.803 回答
2
cat file.xml | \
perl -p -i -e 'open(F, ">", ($1).".xml") if /<article id="(\d+)"/; print F;' 

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

于 2012-07-11T19:38:58.760 回答
0

这是 awk 的一个简单想法:

每当您使用文章开始标签点击一行时,将计数器变量加一。然后,对每一行进行系统调用,如“echo $0 >> file$COUNTER”。这应该很容易实现

于 2012-07-11T19:34:35.380 回答