如何使用Nokogiri在NodeSet中添加子节点

时间:2012-04-24 14:31:33

标签: ruby xml nokogiri

我正在尝试在根节点下添加子节点..我尝试使用以下xml,但这不起作用。我是Ruby和Nokogiri的新手

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  

我需要在根节点下添加节点,如

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

这对我有用..但我真正需要的是在文档中的特定位置之后添加这些节点。

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

我尝试使用at_xpath('// Catlog'),但它在元素的末尾添加(如你所说)

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

book = Nokogiri::XML::Node.new('book', doc)
pen  = Nokogiri::XML::Node.new('pen', doc)     
.
.

无论如何使用“each”循环而不是逐个添加..我试过这种方式,但这不起作用。

  

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”              。              。              。
     }
     结束
    doc&lt;&lt;节点

代码可能有误,但我想这样做。还有一个就是..我可以将所有元素添加为NodeSet而不是Node。请更正我的代码。

提前致谢


  1. 嵌套的OpenStruct似乎没有正常工作。我尝试了下面的例子

    商店

    的目录集合
    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')
    )]
    
  2. 我想访问第一个“catalogProductInfo”的“productType”,我说“collection.catalogList.catalogProductInfo.productType.content” 我得到以下错误

    #(NoMethodError)的未定义方法`productType'

    OpenStruct是否支持嵌套OpenStruct我想使用OpenStruct和Nokogiri以下面的格式构建XML?

    <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>
    

    我想使用Nokogiri和OpenStruct实现这一点,但我不确定OpenStruct是否可行,因为它缺乏嵌套功能。有没有其他方法可以使用JSon实现这一点而没有任何明显的限制?请更正我之前的代码。

1 个答案:

答案 0 :(得分: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

<<应该在元素结尾之前附加节点。

更新

更新后的问题并简化了@ 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

更新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