【发布时间】:2014-02-08 08:07:17
【问题描述】:
我最近参与了一项涉及将 XML 转换为 JSON 的编码练习。明智的做法是使用 JSON 和 ActiveSupport gems as described here. 这就是我在生产中所做的,但这并不能使我成为更好的编码员。所以,我编写了自己的脚本,并且它有效,但坦率地说,我认为这很可怕。我的问题是,怎么可能更好?我可以使用哪些类型的技术和方法来使这个脚本更简单、更易读、更专业?
作为参考,我们从以下 input.html 开始(干净 - 没有边缘情况):
<html>
<body>
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>
<ul>
<li>A</li>
<li>B</li>
</ul>
</li>
</ul>
</body>
</html>
JSON 输出如下所示:
{ "html": { "body": { "ul": { "li": ["Item One", "Item Two", { "ul": { "li": ["A", "B"] } } ] } } }
这是脚本 - *xml_to_json.rb*:
#!/usr/bin/env ruby
def ucode_strip(obj)
#remove weird whitespace
return obj.gsub(/\A[[:space:]]+|[[:space:]]+\z/, '')
end
def element?(obj)
#returns true if text is an xml element --e.g. "<html>"
if ucode_strip(obj) =~ /\A<.*?>/
true
end
end
def element(obj)
#returns html element name --e.g. "<html>" => html, "html" => nil
stripped = ucode_strip(obj)
parts = stripped.split(/>/)
return parts[0].sub(/</, '')
end
def value?(obj)
#does the line contain information inside of tags <tag>value</tag>
parts = obj.split(/>/)
unless !parts[1]
true
end
end
def value(obj)
#returns the value of an xml element --e.g. "<li>item</li>" => "item"
parts = obj.split(/\</)
parts[0]
end
def convert_file(file)
text = File.read(file.to_s)
lines = text.split(/\n/)
last_tag = nil
same_tags = nil
multiple_values = []
json = "{ "
lines.each do |line|
clean = ucode_strip(line)
if line =~ /<.*?>/
unless clean =~ /\A<\// #<opening tag>
line_elements = clean.split(/>/)
tag = "\"" + element(line) + "\"" + ':'
if line_elements[1]
#there's more data in this line, not just a tag
unless same_tags == true
same_tags = true
json += tag + " ["
last_tag = element(line)
else
json += ", "
end
json += "\"" + value(line_elements[1]) + "\""
else
#this line only contains an opening tag
same_tags = false #stop building list
unless element(line) == last_tag #the previous line started with the same tag
json += tag += " { "
else
json += ", { "
end
last_tag = tag
end
else #</closing tag>
if same_tags == true
#we have a closing tag while building a list
same_tags = false #stop building list
json += "] } " #first close list, then bracket
else
if clean =~ /#{last_tag}/
json += " } ] " #there's an open list we have to
else
json += " } " #no open list, just close bracket
end
end
end
end
end
return json
end
input = ARGV.first
puts convert_file(input)
正如我所说,这可行,但我知道它可能会更好。我意识到几乎没有边缘情况处理,但我更关心我处理整体数据的方式。有人建议使用 ruby 列表作为堆栈来存储嵌套的 JSON,但我还没有完全弄清楚。任何帮助将不胜感激 - 如果您已经走到这一步,感谢您的阅读。
【问题讨论】:
标签: ruby-on-rails ruby xml json data-structures