2017-05-05 21 views
0

我正在使用HTTParty从第三方获取XML文档。 HTTParty使用MultiXML,默认情况下使用Nokogiri将返回的文档解析为一组Ruby对象。 XML文档中的一些节点应该是“1或更多”或“0或更多”元素(又名序列)的数组,但是当它们仅包含单个元素时,它们仅作为父元素的值返回,而不是数组中的单个项目。托管这些XML文件的一方还为文档提供了一个XSD,其中包含有关哪些节点应该是序列的信息。我知道Nokogiri有一个Schema实用程序用于根据XSD验证文档,但是有没有一种方法可以使用模式向文档解析器提供类型提示,以便这些数组节点在返回的Ruby集合中正确表示?使用XSD将XML文档解析为Ruby集合以提示类型

例如,给定以下简略XML文档:

xml_doc = <<EOT 
<Get_Workers_Response> 
    <Response_Data> 
    <Worker> 
     <Personal_Data> 
     <Contact_Data> 
      <Address_Data> 
      <Address_Line_Data>123 A Street</Address_Line_Data> 
      </Address_Data> 
     </Contact_Data> 
     </Personal_Data> 
    </Worker> 
    </Response_Data> 
</Get_Workers_Response> 
EOT 

的引入nokogiri解析器输出:

MultiXml.parser # => MultiXml::Parsers::Nokogiri 
pp MultiXml.parse xml_doc 
{"Get_Workers_Response"=> 
    {"Response_Data"=> 
    {"Worker"=> 
     {"Personal_Data"=> 
     {"Contact_Data"=> 
      {"Address_Data"=>{"Address_Line_Data"=>"123 A Street"}}}}}}} 

当根据模式应该是:

{"Get_Workers_Response"=> 
    {"Response_Data"=> 
    {"Worker"=> # An array of worker data 
     [{"Personal_Data"=> 
     {"Contact_Data"=> # An array of Address line data 
      {"Address_Data"=>{"Address_Line_Data"=>["123 A Street"]}}}}]}}} 

我没有被MultiXML/Nokogiri困住,所以如果有一个更好的解析器用于这种情况,我可以给予它是一个尝试。

+0

请阅读“[mcve]”。你给我们的数据,但没有告诉我们你如何得到Nokogiri的输出,这对于这个问题是至关重要的。 MultiXML允许使用多个不同的XML解析器。 Nokogiri不会返回一个Hash,所以其他事物正在处理数据;可能是MultiXML,或者它使用Ox,它返回一个Hash。使用Nokogiri本身的处理非常简单,除了YMMV之外,我不会打扰其他任何东西。 –

+0

我已经将示例更新为我用来测试的确切ruby。 MultiXML确实使用Nokogiri作为解析器。 –

回答

0

你的问题没有得到很好的解答,但它听起来像你可能不能正确解析数据。它可以始终获得一个或多个节点作为阵列的内容,所以你只需要担心处理数组:

require 'nokogiri' 

doc = Nokogiri::XML(<<EOT) 
<xml> 
<Get_Workers_Response> 
    <Address_Line_Data>123 A Street</Address_Line_Data> 
</Get_Workers_Response> 
</xml> 
EOT 

ald = doc.search('Address_Line_Data').map(&:text) # => ["123 A Street"] 

ald是在这一点上文本的数组。

如果有两个记录,假设他们是这样的:

doc = Nokogiri::XML(<<EOT) 
<xml> 
<Get_Workers_Response> 
    <Address_Line_Data>123 A Street</Address_Line_Data> 
    <Address_Line_Data>456 A Street</Address_Line_Data> 
</Get_Workers_Response> 
</xml> 
EOT 

ald = doc.search('Address_Line_Data').map(&:text) # => ["123 A Street", "456 A Street"] 

ald仍然是一个字符串数组。