新手问题 Rails 怎么解析 post 过来的 XML?

developlee · 2016年08月19日 · 最后由 ruchee 回复于 2016年08月24日 · 4536 次阅读

Ruby 小白,求教大家,微信服务器 post xml 到我的服务器上,我该怎么解析?网上查到有些用 params[:xml][:message] 之类的,但是貌似 rails4 以后不能用了😢

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[fromUser]]></FromUserName>
  <CreateTime>1348831860</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[this is a test]]></Content>
  <MsgId>1234567890123456</MsgId>
</xml>

我要怎么获得 this is a test ?

在 post body 里面吗?用 Nokogiri 解析 request.body.read

#1 楼 @Rei #2 楼 @hammer

@xmldoc = Nokogiri::XML(request.body.read).xpath('//Content')

我是这样写的,但是返回的是

<Content><![CDATA[this is a test]]></Content>

#3 楼 @developlee 看起来没问题啊。

#3 楼 @developlee Nokogiri::XML(request.body.read).xpath('//Content').text

thanks! 我的问题解决了,感谢👍 @Rei

看起来是 微信的包吧 前面都推荐 Nokogiri Hash.from_xml 比较直接简单

xml 的模板推荐你用roxml

require "roxml"

module Wechat
  module Message
    class Base
      include ROXML
      xml_name :xml

      xml_accessor :ToUserName, cdata: true
      xml_accessor :FromUserName, cdata: true
      xml_reader   :CreateTime, as: Integer
      xml_reader   :MsgType, cdata: true

      def initialize
        @CreateTime = Time.zone.now.to_i
      end

      def to_xml
        super.to_xml(encoding: "UTF-8", indent: 0, save_with: 0)
      end
    end
  end
end


# <xml>
# <ToUserName><![CDATA[toUser]]></ToUserName>
# <FromUserName><![CDATA[fromUser]]></FromUserName>
# <CreateTime>12345678</CreateTime>
# <MsgType><![CDATA[text]]></MsgType>
# <Content><![CDATA[Hello]]></Content>
# </xml>
module Wechat
  module Message
    class Text < Base
      xml_accessor :Content, cdata: true
      def initialize
        super
        @MsgType = "text"
      end
    end
  end
end

破费

#5 楼 @Rei 另外想问问,能否将返回的 xml 保存为一个对象或者是数组? #6 楼 @zhang_soledad 有具体例子能提供一个吗?刚开始学 rails,然后用 rails 做微信开发,确实问题挺多的,能帮忙,感激不尽

#8 楼 @developlee 我觉得保存原始字符串好了,下次取出再解析,对象序列化反序列化说不定有信息丢失(例如 hash 不支持 xml 属性)。或者数据库原生支持 xml 字段 也可以试试。

如果是微信的,Hash.from_xml完全适用

xml = <<-XML
<?xml version="1.0" encoding="UTF-8"?>
   <hash>
     <foo>1</foo>
     <bar>2</bar>
   </hash>
XML

hash = Hash.from_xml(xml)
# => {"hash"=>{"foo"=>1, "bar"=>2}}

有 api 文档 多试多查

config.middleware.insert_after ActionDispatch::ParamsParser, ActionDispatch::XmlParamsParser

添加下这个配置,params[:xml][:EventKey] 之类的就能直接使用

#11 楼 @michael_miao91 这个试过,有个 action-xml_parser 的 gem 来着,后来安装之后,启动出错误了😢

#12 楼 @developlee rails4.2,没有遇到错误 ( ⊙ o ⊙ ) 啊!

在一个 action 解析 xml, 要安装个 ActionDispatch::XmlParamsParser middleware, 太正式了吧

#13 楼 @michael_miao91 可能我配置有点问题,我是在 config/application.rb 这个文件加的

config.middleware.insert_after ActionDispatch::ParamsParser, ActionDispatch::XmlParamsParser

Rails 的话 ActiveSupport 里提供了一个快速反序列化 XML 到 Hash 的方法,没记错是 Hash.from_xml 可以查查文档

一看就是对接微信接口的 😄

def xml_to_hash (xml)
  begin
    require 'active_support/core_ext/hash/conversions'
    Hash.from_xml(xml)['xml']
  rescue
    {}
  end
end
developlee 关闭了讨论。 04月13日 22:18
需要 登录 后方可回复, 如果你还没有账号请 注册新账号