Вопрос по ruby, xml, nokogiri – Как добавить дочерние узлы в NodeSet с помощью Nokogiri

7

Я пытаюсь добавить дочерние узлы под корневым узлом. Я пробовал использовать ниже XML, но это не работает. Я новичок для Руби и Нокогири

<code>builder = Nokogiri::XML::Builder.with(@doc) do |xml|   
  nodes = Nokogiri::XML::NodeSet.new(@doc, [])   
  [].each {|nodes_one_by_one|  
    << nodes_one_by_one.Book  
    << nodes_one_by_one.Pen 
  }      
end  
</code>

Мне нужно добавить узлы ниже корневого узла, как это

<code><Catalog>
    <Book>abc</Book>
    <Book_Author>Benjamin</Book_author>
</code>

Это хорошо работает для меня ... но что мне действительно нужно, это добавить эти узлы после определенной позиции в документе.

<code><Catalog>
    <!-- 
    <Book>abc</Book>
    <Book_Author>Benjamin</Book_author>
    -->
    <Interface></Interface>
    <Dialog></Dialog>
    <Manifest></Manifest>
</Catalog>
</code>

я попробовал это с at_xpath ("// Catlog"), но он добавляет в конце элемента (как вы сказали)

<code> <Catalog>
    <Interface></Interface>
    <Dialog></Dialog>
    <Manifest></Manifest>
     <!-- 
      <Book>abc</Book>
      <Book_Author>Benjamin</Book_author>
     -->
</code>
<code>book = Nokogiri::XML::Node.new('book', doc)
pen  = Nokogiri::XML::Node.new('pen', doc)     
.
.
</code>

Есть ли в любом случае цикл с использованием «каждого» вместо того, чтобы добавлять по одному ... Я попробовал этот способ, но это не работает.

builder = Nokogiri::XML::Builder.with(doc) do |xml|
nodes = Nokogiri::XML::Node.new(doc, [])
[].each {|child_list_element|
child_list_element.Book "value" child_list_element.Pen "value" child_list_element.Diary "value" child_list_element.Pen_stand "value" child_list_element.Pencil "value" . . .
}
end
doc << nodes

Код может быть неправильным, но я хочу сделать это так. Еще один это как ... Могу ли я добавить все элементы как NodeSet вместо Node. Пожалуйста, исправьте мой код.

заранее спасибо

Nested OpenStruct doesn't seem to be working fine. I tried with an example below

Catalog collection of Store
<code>require 'ostruct'
require 'nokogiri'

collection = [
OpenStruct.new(:catalogStoreNumber => '657758',
:catalogStoreId => 'CTH6536',
:catalogStoreLocation => 'UnitedStates', 
:catalogOwnerId => 'TYCT11190',
:catalogOwner => 'McGrawHill Pub.',
:catalogList => OpenStruct.new(
    :catalogProductInfo => OpenStruct.new(
    :productType => 'Book',
    :productName => 'The Client',
    :productId => 'CRSUS113246A',
    :productCategory => 'Crime And Suspense',
    :productSubcategory => 'Vintage Books',  
    :productPrice => '45.50 USD',
    :productAuthor => OpenStruct.new(
            :authorFirstName =>'John Grisham',
    :authorMiddleName=> 'Willburt',
    :authorContact => '19876648981')),
:catalogProductInfo => OpenStruct.new(
    :productType => 'Pen',
    :productName => 'Reynolds',
    :productId => 'PRREY546647',
    :productCategory => 'Misc. Stationary',
    :productSubcategory => 'Stationery Items',  
    :productPrice => '3.00 USD',
    :productManufacturer => 'Reynolds Inc.',
    :productAuthor => OpenStruct.new(
        :authorFirstName => 'Ryan Reynolds',
    :authorMiddleName => 'William',
    :authorContact => '16577589898')),
:catalogListType => 'ProductCollection',
:catalogListSource => 'Web'
),
:catalogVerificaitionLog => OpenStruct.new(
    :catalogVerificationStatus => 'Verified',
:catalogVerificationDateTime => '2012-03-12T13:00:15+5:30',
:catalogVerificationId => '64774A',
:catalogVerificationRequestedBy => 'user_121')
)]
</code>

я хочу получить доступ к & quot; productType & quot; первого & quot; catalogProductInfo & quot; и я сказал & quot; collection.catalogList.catalogProductInfo.productType.content & quot; и я получаю ошибку ниже

& quot; неопределенный метод `productType & apos; для # (NoMethodError)

Есть ли в OpenStruct поддержка вложенного OpenStruct? Хочу создать XML в следующем формате, используя OpenStruct и Nokogiri?

<code><CatalogOrder>
    <CatalogStoreNumber>657758</CatalogStoreNumber>
    <CatalogStoreId>CTH6536</CatalogStoreId>
    <CatalogStoreLocation>UnitedStates</CatalogStoreLocation>
    <CatalogOwnerId>TYCT11190</CatalogOwnerId>
    <CatalogOwner>McGrawHill Pub.</CatalogOwner>
    <CatalogList>
        <CatalogProductInfo>
        <ProductType>Book</ProductType>
        <ProductName>The Client</ProductName>                          
        <ProductId>CRSUS113246A</ProductId>
        <ProductCategory>Crime And Suspense</ProductCategory>
        <ProductSubCategory>Vintage Books</ProductSubCategory>
        <ProductPrice>45.50 USD</ProductPrice>
        <ProductAuthor>
            <AuthorFirstName>John Grisham</AuthorFirstName>
        <AuthorMiddleName>Willbur</AuthorMiddleName>
        <AuthorContact>19876648981</AuthorContact>
        </ProductAuthor>
    </CatalogProductInfo>
    <CatalogProductInfo>
        <ProductType>Pen</ProductType>
        <ProductName>Reynolds</ProductName>                        
        <ProductId>PRREY546647</ProductId>
        <ProductCategory>Misc. Stationary</ProductCategory>
        <ProductSubCategory>Stationary Items</ProductSubCategory>
        <ProductPrice>3.00 USD</ProductPrice>
        <ProductAuthor>
        <AuthorFirstName>Ryan Reynolds</AuthorFirstName>
        <AuthorMiddleName>William</AuthorMiddleName>
        <AuthorContact>16577589898</AuthorContact>
        </ProductAuthor>
    </CatalogProductInfo>
    <CatalogListType>ProductCollection</CatalogListType>
    <CatalogListSource>Web</CatalogListSource>
</CatalogList>
<CatalogVerificationLog>
    <CatalogVerificationStatus>Verified</CatalogVerificationStatus>
    <CatalogVerificationDateTime>2012-03-12T13:00:15+5:30</CatalogVerificationDateTime>
    <CatalogVerificationId>64774A</CatalogVerificationId>
    <CatalogVerificationRequestedBy>User_121</CatalogVerificationRequestedBy>
</CatalogVerificationLog>
</code>

Я хочу добиться этого с помощью Nokogiri и OpenStruct, но я не уверен, возможно ли это с OpenStruct, так как в нем отсутствуют возможности вложения. Есть ли другой способ использовать JSon для достижения этой цели без каких-либо серьезных ограничений? Пожалуйста, исправьте мой предыдущий код.

Nokogiri::XML::Builder это хорошо для создания XML-документа с нуля, но у вас уже есть с ним работать, так что, насколько я знаю, нет причин использовать его. Jamie

Ваш Ответ

1   ответ
10

Если я вас правильно понимаю, примерно то, что вы ищете:

doc = Nokogiri::XML(original_xml_string) 

catalog = doc.at_css('Catalog') # #at_css will just grab the first node.
                                # use #css if you want to loop through several.
                                # alternatively just use doc.root

book = Nokogiri::XML::Node.new('Book', doc)
book_author = Nokogiri::XML::Node.new('Book_Author', doc)

book.content = 'abc'
book_author.content  = 'benjamin'

catalog << book
catalog << book_author

<< следует добавить узлы непосредственно перед концом элемента.

Update

После обновленного вопроса и упрощенного предложения @ Phrogz это должно соответствовать вашим требованиям:

require 'nokogiri'

xml = <<'XML'
<Catalog>
  <Interface></Interface>
  <Dialog></Dialog>
  <Manifest></Manifest>
</Catalog>
XML

doc = Nokogiri::XML(xml) 
catalog = doc.root

catalog.first_element_child.before("<Book_Author>abc</Book_Author>")
catalog.first_element_child.before("<Book>benjamin</Book>")

puts doc.to_xml

Update 2

Чтобы перебрать коллекцию, добавить узлы динамически и, используя NodeSet, попробуйте следующее:

require 'nokogiri'
require 'ostruct'

xml = <<-'XML'
<Catalog>
  <Interface></Interface>
  <Dialog></Dialog>
  <Manifest></Manifest>
</Catalog>
XML

collection = [
  OpenStruct.new(book: '1984', pen: 'George Orwell'),
  OpenStruct.new(book: 'Thinking, Fash and Slow', pen: 'Daniel Kahneman')
]

doc = Nokogiri::XML(xml) 
catalog = doc.root

node_set = Nokogiri::XML::NodeSet.new(doc)
collection.each do |object|
  book = Nokogiri::XML::Node.new('Book', doc)
  book_author = Nokogiri::XML::Node.new('Book_Author', doc)

  book.content = object.book
  book_author.content = object.pen

  node_set << book
  node_set << book_author
end

catalog.first_element_child.before(node_set)

puts doc.to_xml
@ user1023627 Чтобы вставить узел в качестве нового первого дочернего элемента, вставьте его перед существующим первым дочерним элементом:catalog.first_element_child.before("<Book>abc</Book>").
Спасибо за подсказку @Phrogz, не знал этого.
Обратите внимание, что<< Можно также принять строку, так что вы можете просто сделать:catalog << "<Book>abc</Book>"
привет phroz и Джейми. я обновил свой вопрос. не могли бы вы посмотреть на это. user1023627
Спасибо Phroz и Джейми, которые были действительно полезны. Я буду работать над этим и вернусь к вам. user1023627

Похожие вопросы