3

そこで、XML ファイルを構築しようとしていますが、その構築方法の性質上、自然な入れ子構造の外に要素を追加する必要があります。例えば:

builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
  xml.Data {
    xml.Groups do |inner|
      inner.send(:"GroupType", "test")
    end
    # Insert child element into Groups element.
  }
end

XML を次のようにしたい:

<Data>
  <Groups>
    <GroupType>test</GroupType>
    <AnotherNode>13</AnotherNode>
  </Groups>
</Data>

私のコメントが最初のコードサンプルにある場所<AnotherNode>に追加されます。

比較的単純なはずですが、私の人生では理解できません。おそらく、ブロックを検索できるようにする必要がありますか、それとも、ブロックを作成して使用するときに参照する必要がありますか?

余談ですが、私は Nokogiri の要素が既にたくさん含まれているプロジェクトを引き継いでおり、次のようなセレクターがあります。

xml_file = Nokogiri::XML(xml)

(xml_file/:RootNode).each do |root|
  (root/:SomeItem).each do |si|
    ...
  end
end

..それでも、ドキュメントでそのようなものを見つけることができませんか? それは何ですか?

4

4 に答える 4

3

Nokogiri :: XML :: Builderのみを使用する場合は、次のようにする必要があります。

require 'nokogiri'

builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
  xml.Data {
    xml.Groups {
      xml.GroupType "test"
      xml.AnotherNode "13"
    }
  }
end

puts builder.to_xml
Which outputs:

=> <?xml version="1.0" encoding="UTF-8"?>
   <Data>
     <Groups>
       <GroupType>test</GroupType>
       <AnotherNode>13</AnotherNode>
     </Groups>
   </Data>

BuilderはDSLであり、機能のセットが限られている便利なものとして設計されています。「ビルダーウェイ」で実行したくない場合は、「旧式」で既存のXMLノードを取得し、その上に構築することができます。

require 'nokogiri'

builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
  xml.Data {
    xml.Groups {
      xml.GroupType "test"
    }
  }
end

これにより、Builderオブジェクト内に必要なベースXMLが作成されました。それをXMLとしてレンダリングし、それをNokogiri :: XML :: Documentに再解析してから、次のように処理します。

doc = Nokogiri::XML(builder.to_xml)
doc.at('GroupType').add_next_sibling("<AnotherNode>13</AnotherNode>")
puts doc.to_xml

=> <?xml version="1.0" encoding="UTF-8"?>
   <Data>
     <Groups>
       <GroupType>test</GroupType><AnotherNode>13</AnotherNode>
     </Groups>
   </Data>

doc = Nokogiri::XML(builder.to_xml)
doc.at('Groups').add_child("<AnotherNode>13</AnotherNode>")
puts doc.to_xml

=> <?xml version="1.0" encoding="UTF-8"?>
   <Data>
     <Groups>
       <GroupType>test</GroupType>
     <AnotherNode>13</AnotherNode></Groups>
   </Data>

上記の2つの方法のいずれも、構文的に同じものをレンダリングしますが、見た目が異なるだけです。

複雑でファンキーになり、次のようにすることもできます。

builder = Nokogiri::XML::Builder.with(
  Nokogiri::XML(
    builder.to_xml
  ).at('Groups') << "<AnotherNode>13</AnotherNode>"
)
puts builder.to_xml

=> <?xml version="1.0" encoding="UTF-8"?>
   <Data>
     <Groups>
       <GroupType>test</GroupType>
     <AnotherNode>13</AnotherNode></Groups>
   </Data>
于 2012-12-03T11:50:55.050 に答える
3

事実から2年後にこれにぶつかり、受け入れられた答えは必要以上に複雑だと思いました.

問題は、ここで XML フラグメントを構築していることですが、デフォルトでは、Nokogiri のビルダーは完全なドキュメントを構築していると想定しています。XML ドキュメントにはルート ノードが 1 つしかありません。

1 つのオプションは、次のように完全なドキュメントを構築してから、ルートの子を取得することです。

<DISPOSABLE_OUTER_NODE>
  <Data>
    <Groups>
      <GroupType>test</GroupType>
     </Groups>
  </Data>
  <AnotherNode>13</AnotherNode>
</DISPOSABLE_OUTER_NODE>

しかし、より良い「断片的な」方法があります。空のフラグメントを作成してから、新しいドキュメントではなく、ビルダーにそれを処理させます。

frag = Nokogiri::XML::DocumentFragment.parse("")

Nokogiri::XML::Builder.with( frag ){ |b|
  b.Data do
    b.Groups do
      b.GroupType "test"
    end
  end

  b.AnotherNode "13"
}

puts frag.to_xml

次に、変更するドキュメントに貼り付けます。

withのこぎりに後発かも。しかし、それは私が抱えていた問題に対するエレガントな解決策なので、ここに属していると思いました.

于 2015-03-23T19:59:49.870 に答える
2

私も同じ問題を抱えていました。

次のコードは、あなたが望むことを(多かれ少なかれ)行うと思います。

builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
  xml.Data {
    p = nil
    xml.Groups do |inner|
      inner.send(:"GroupType", "test") do |n|
        p = n.parent
      end
    end
    # Insert child element into Groups element.
    xb = Nokogiri::XML::Builder.new({}, p)
    xb.someOtherChild
  }
end
于 2013-01-29T15:56:00.933 に答える