【问题标题】:Ruby - Convert XML to JSON without using GemsRuby - 在不使用 Gems 的情况下将 XML 转换为 JSON
【发布时间】: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


    【解决方案1】:

    convert_file 方法过于复杂,将解析器和构建器的逻辑混合在一起,难以阅读、重用和扩展,我建议将这个逻辑分离出来。

    用于解析 xml 文件的代码是调用解析器,据我所知有三种解析器,即 SAX、DOM、StAX,您可以通过 google 找到一些参考,看看如何实现。

    生成json代码的代码是调用builder,是一种设计模式,你也可以通过google找到更多信息。

    堆栈是一种数据结构,您可以在实现解析器和构建器时使用它。

    【讨论】:

      猜你喜欢
      • 2014-11-27
      • 2018-12-23
      • 2016-01-29
      • 2012-11-01
      • 2013-06-04
      • 1970-01-01
      • 1970-01-01
      • 2015-01-29
      相关资源
      最近更新 更多