Как объединить два XML файла с Nokogiri - PullRequest
0 голосов
/ 27 апреля 2020

Я пытаюсь объединить два отдельных, но связанных файла с Nokogiri. Я хочу объединить «product» и «price of product», если «ItemNumber» совпадает.

Я загрузил документы, но не знаю, как их объединить.

Файл продукта:

<Products>
  <Product>
    <Name>36-In. Homeowner Bent Single-Bit Axe Handle</Name>
    <ProductTypeId>0</ProductTypeId>
    <Description>This single bit curved grip axe handle is made for 3 to 5 pound axes. A good quality replacement handle made of American hickory with a natural wax finish. Hardwood handles do not conduct electricity and American Hickory is known for its strength, elasticity and ability to absorb shock. These handles provide exceptional value and economy for homeowners and other occasional use applications. Each Link handle comes with the required wedges, rivets, or epoxy needed for proper application of the tool head.</Description>
    <ActiveFlag>Y</ActiveFlag>
    <ImageFile>100024.jpg</ImageFile>
    <ItemNumber>100024</ItemNumber>
    <ProductVariants>
      <ProductVariant>
        <Sku>100024</Sku>
        <ColorName></ColorName>
        <SizeName></SizeName>
        <SequenceNo>0</SequenceNo>
        <BackOrderableFlag>N</BackOrderableFlag>
        <InventoryLevel>0</InventoryLevel>
        <ColorCode></ColorCode>
        <SizeCode></SizeCode>
        <TaxableFlag>Y</TaxableFlag>
        <VariantPromoGroupCode></VariantPromoGroupCode>
        <PricingGroupCode></PricingGroupCode>
        <StartDate xsi:nil="true"></StartDate>
        <EndDate xsi:nil="true"></EndDate>
        <ActiveFlag>Y</ActiveFlag>
      </ProductVariant>
    </ProductVariants>
  </Product>
</Products>

Поля цен на продукт:

<ProductPricing>
  <ItemNumber>100024</ItemNumber>
  <AcquisitionCost>8.52</AcquisitionCost>
  <MemberCost>10.7</MemberCost>
  <Price>14.99</Price>
  <SalePrice xsi:nil="true"></SalePrice>
  <SaleCode>0</SaleCode>
</ProductPricing>

Я ищу файл, подобный следующему:

<Products>
  <Product>
    <Name>36-In. Homeowner Bent Single-Bit Axe Handle</Name>
    <ProductTypeId>0</ProductTypeId>
    <Description>This single bit curved grip axe handle is made for 3 to 5 pound axes. A good quality replacement handle made of American hickory with a natural wax finish. Hardwood handles do not conduct electricity and American Hickory is known for its strength, elasticity and ability to absorb shock. These handles provide exceptional value and economy for homeowners and other occasional use applications. Each Link handle comes with the required wedges, rivets, or epoxy needed for proper application of the tool head.</Description>
    <ActiveFlag>Y</ActiveFlag>
    <ImageFile>100024.jpg</ImageFile>
    <ItemNumber>100024</ItemNumber>
    <ProductVariants>
      <ProductVariant>
        <Sku>100024</Sku>
        <ColorName></ColorName>
        <SizeName></SizeName>
        <SequenceNo>0</SequenceNo>
        <BackOrderableFlag>N</BackOrderableFlag>
        <InventoryLevel>0</InventoryLevel>
        <ColorCode></ColorCode>
        <SizeCode></SizeCode>
        <TaxableFlag>Y</TaxableFlag>
        <VariantPromoGroupCode></VariantPromoGroupCode>
        <PricingGroupCode></PricingGroupCode>
        <StartDate xsi:nil="true"></StartDate>
        <EndDate xsi:nil="true"></EndDate>
        <ActiveFlag>Y</ActiveFlag>
      </ProductVariant>
    </ProductVariants>
  </Product>
  <ProductPricing>
    <ItemNumber>100024</ItemNumber>
    <AcquisitionCost>8.52</AcquisitionCost>
    <MemberCost>10.7</MemberCost>
    <Price>14.99</Price>
    <SalePrice xsi:nil="true"></SalePrice>
    <SaleCode>0</SaleCode>
  </ProductPricing>
</Products>

Вот код, который у меня есть:

require 'csv'
require 'nokogiri'

xml = File.read('lateApril-product-pricing.xml')
xml2 = File.read('lateApril-master-date')

doc = Nokogiri::XML(xml)
doc2 = Nokogiri::XML(xml2)

pricing_data = []
item_number = []

doc.xpath('//ProductsPricing/ProductPricing').each do |file|

  itemNumber = file.xpath('./ItemNumber').first.text
  variant_Price = file.xpath('./Price').first.text

  pricing_data << [ itemNumber, variant_Price ]

  item_number << [ itemNumber ]
end 

puts item_number ## This prints all the item number but i have no idea how to loop through them and combine them with Product XML

doc2.xpath('//Products/Product').each do |file|
  itemNumber = file.xpath('./ItemNumber').first.text #not sure how to write the conditions here since i don't have pricing fields available in this method
end 

1 Ответ

0 голосов
/ 28 апреля 2020

Попробуйте это на:

require 'nokogiri'

doc1 = Nokogiri::XML(<<EOT)
<Products>
  <Product>
    <Name>36-In. Homeowner Bent Single-Bit Axe Handle</Name>
  </Product>
</Products>
EOT

doc2 = Nokogiri::XML(<<EOT)
<ProductPricing>
  <ItemNumber>100024</ItemNumber>
</ProductPricing>
EOT

doc1.at('Product').add_next_sibling(doc2.at('ProductPricing'))

Что приводит к:

puts doc1.to_xml

# >> <?xml version="1.0"?>
# >> <Products>
# >>   <Product>
# >>     <Name>36-In. Homeowner Bent Single-Bit Axe Handle</Name>
# >>   </Product><ProductPricing>
# >>   <ItemNumber>100024</ItemNumber>
# >> </ProductPricing>
# >> </Products>

Пожалуйста, , когда вы спросите, удалите входной пример и ожидаемый результат в абсолют, минимум, минимум. Все, что находится за его пределами, тратит пространство, время, глаза и процессор мозга.

Это непроверенный код , но с этого я бы начал, если бы собирался объединить два файла, содержащие , кратное <ItemNumber> узлы:

require 'nokogiri'

doc1 = Nokogiri::XML(<<EOT)
<Products>
  <Product>
    <Name>36-In. Homeowner Bent Single-Bit Axe Handle</Name>
    <ItemNumber>100024</ItemNumber>
  </Product>
</Products>
EOT

doc2 = Nokogiri::XML(<<EOT)
<ProductPricing>
  <ItemNumber>100024</ItemNumber>
</ProductPricing>
EOT

# build a hash containing the item numbers in doc1 for each product
doc1_products_by_item_numbers = doc1.search('Product').map { |product|
  item_number = product.at('ItemNumber').value
  [
    item_number,
    product
  ]
}.to_hash

# build a hash containing the item numbers in doc2 for each product pricing
doc2_products_by_item_numbers = doc2.search('ProductPricing').map { |pricing| 
  item_number = pricing.at('ItemNumber').value
  [
    item_number,
    pricing
  ]
}.to_hash

# append doc2 entries to doc1 after each product based on item numbers
doc1_products_by_item_numbers.keys.each { |k|
  doc1_products_by_item_numbers[k].add_next_sibling(doc2_products_by_item_numbers[k])
}
...