1

これが私が達成しようとしている変換の例です。ソース XML:

<cats>
  <cat>John</cat>
  <cat>Peter</cat>
</cats>

結果:

{'cats' => ['John', 'Peter']}

また、ソース XML'cats'に 1 つしかない場合でも、結果のハッシュの値を配列にしたいと考えています。<cat>

したがって、パーサーに次のルールを適用してもらいたいと思います。

nodexyzsに名前付きの 1 つ以上の子ノードが含まれるxyz(他のノードは含まれない) 場合、 nodexyzsは、結果のハッシュで名前付きの配列として表される必要がありますxyzs(配列の各要素は、対応する要素の内容である必要がありますxyz)。

XmlSimple libを使用して実現する方法は次のとおりです。

XmlSimple.xml_in('cats.xml',{:forcearray=>['cat'], :grouptags=>{"cats"=>"cat"}})

ただし、ターゲット要素のすべての名前を入力する必要があり、XmlSimple 内で forcearray/grouptags の動作を定義する方法は他にないようです。

すべての名前を抽出して xml_in メソッドに渡す前処理ルーチンをハックするのは難しくありませんが、これを行うためのより洗練された (つまり、既に記述された) 方法があるのではないでしょうか?

(変換が可能な場合は、他のXML解析ライブラリを喜んで使用します)


UPD :問題がある場合、私の最終目標は、結果のハッシュをMongoDBに保存することです(つまり、全体的な変換はXML -> BSONです)


UPD2 : 繰り返しますが、配列として扱われるべき要素の名前を指定したくありません。ライブラリに魔法をかけてもらいたいのです。

4

2 に答える 2

1

最初に で終わる要素名を見つけますs:

names = doc.search('*[name()$="s"]').map(&:name).uniq
#=> ["cats"]

あとはマッピングとハッシュだけです:

Hash[names.map{|name| [name, doc.search("#{name} > #{name.sub /s$/, ''}").map(&:text)]}]
#=> {"cats"=>["John", "Peter"]}
于 2013-10-18T06:52:49.123 に答える
1

Nokogiri を使用すると、次のコードを記述できます。

require 'inflector'
require 'nokogiri'

def get_xml_stuff(xml, singular)
  plural = Inflector.pluralize(singular)
  return_hash = {plural => []}
  xml.xpath("*/#{plural}/#{singular}").each { |tag| return_hash[plural] << tag.text}
  return return_hash
end

私のテストによると、これは XmlSimple コードに一致する単純なケースを解決します。あなたのさらなる要件について:

nodexyzsに名前付きの 1 つ以上の子ノードが含まれるxyz(他のノードは含まれない) 場合、 nodexyzsは、結果のハッシュで名前付きの配列として表される必要がありますxyzs(配列の各要素は、対応する要素の内容である必要がありますxyz)。

def get_xml_stuff(xml, singular)
  plural = Inflector.pluralize(singular)
  return_hash = {plural => []}
  path = xml.xpath("*/#{plural}/#{singular}")
  path.each { |tag| return_hash[plural] << tag.text} unless path.size != xml.xpath("*/#{plural}/*").children.size
  return return_hash
end

ただし、同じ複数形がファイルに複数回出現する場合は、まだ完全ではありません。


UPD2に応答しています。関数の新しいバージョンは次のとおりです。

def get_xml_stuff(xml, plural)
  singular = Inflector.singularize(plural)
  return_hash = {plural => []}
  path = xml.xpath("./#{singular}")
  path.each { |tag| return_hash[plural] << tag.text} unless path.size != xml.xpath("./*").size
  return return_hash
end

ここでは、複数形の親ノードから開始し、名前付きのすべての子ノードがその単数形の名前である場合、すべての単数形の子ノードを収集します。私の新しいテストコードは次のようになります。

sample_xml = Nokogiri::XML(sample_xml_text)
sample_xml.children.xpath("*").each do |child|
  array = get_xml_stuff(child, child.name)
  p array
end

私の例のようなタグがない場合<pets>、次のように動作するはずです:

sample_xml = Nokogiri::XML(sample_xml_text)
array = get_xml_stuff(sample_xml.children.first, sample_xml.children.first.name)
p array

UPD2 の終了


参考までに、私のテストは次のとおりです。

sample_xml_text = <<-sample
<pets>
  <cats>
    <cat>John</cat>
    <cat>Peter</cat>
  </cats>
  <kitties>
    <kitty>Tibbles</kitty>
    <kitty>Meow-chan</kitty>
    <kitty>Puss</kitty>
  </kitties>
  <giraffes>
    <giraffe>Long Neck</giraffe>
  </giraffes>
  <dogs>
    <dog>Rover</dog>
    <dog>Spot</dog>
    <cat>Peter</cat>
  </dogs>
</pets>
sample

sample_xml = Nokogiri::XML(sample_xml_text)
array = get_xml_stuff(sample_xml, "cat")
p array
array = get_xml_stuff(sample_xml, "kitty")
p array
array = get_xml_stuff(sample_xml, "giraffe")
p array
array = get_xml_stuff(sample_xml, "dog")
p array
于 2013-10-18T04:39:34.897 に答える