Почему Нокогири усекает этот элемент? - PullRequest
1 голос
/ 07 апреля 2011

Я анализирую XML-файл, используя Nokogiri и Ruby 1.9.2.Кажется, все работает нормально, пока я не прочитал Descriptions (ниже).Текст усекается.Вводимый текст:

<Value>The Copthorne Aberdeen enjoys a location proximate to several bars, restaurants and other diversions. This Aberdeen hotel is located on the city’s West End, roughly a mile from the many opportunities to engage in sightseeing or simply shopping the day away. The Aberdeen International Airport is approximately 10 miles from the Copthorne Hotel in Aberdeen.

There are 89 rooms in total at the Copthorne Aberdeen Hotel. Each of the is provided with direct-dial telephone service, trouser presses, coffee and tea makers and a private bath with a bathrobe and toiletries courtesy of the hotel. The rooms are light in color.

The Hotel Copthorne Aberdeen offers its guests a restaurant where they can enjoy their meals in a somewhat formal setting. For something more laid-back, guests may have a drink and a light meal in the hotel bar. This hotel does offer business services and there are rooms for meetings located onsite. The hotel also provides a secure parking facility for those who arrive by private car.</Value>

Но вместо этого я получаю:

g. For something more laid-back, guests may have a drink and a light meal in the hotel bar. This hotel does offer business services and there are rooms for meetings located onsite. The hotel also provides a secure parking facility for those who arrive by private car.

Обратите внимание, что он начинается с g., что больше половины.

Вот полный XML-файл:

<?xml version="1.0" encoding="utf-8"?>
<Hotel>
  <HotelID>1040900</HotelID>
  <HotelFileName>Copthorne_Hotel_Aberdeen</HotelFileName>
  <HotelName>Copthorne Hotel Aberdeen</HotelName>
  <CityID>10</CityID>
  <CityFileName>Aberdeen</CityFileName>
  <CityName>Aberdeen</CityName>
  <CountryCode>GB</CountryCode>
  <CountryFileName>United_Kingdom</CountryFileName>
  <CountryName>United Kingdom</CountryName>
  <StarRating>4</StarRating>
  <Latitude>57.146068572998</Latitude>
  <Longitude>-2.111680030823</Longitude>
  <Popularity>1</Popularity>
  <Address>122 Huntly Street</Address>
  <CurrencyCode>GBP</CurrencyCode>
  <LowRate>36.8354</LowRate>
  <Facilities>1|2|3|5|6|8|10|11|15|17|18|19|20|22|27|29|30|34|36|39|40|41|43|45|47|49|51|53|55|56|60|62|140|154|209</Facilities>
  <NumberOfReviews>239</NumberOfReviews>
  <OverallRating>3.95</OverallRating>
  <CleanlinessRating>3.98</CleanlinessRating>
  <ServiceRating>3.98</ServiceRating>
  <FacilitiesRating>3.83</FacilitiesRating>
  <LocationRating>4.06</LocationRating>
  <DiningRating>3.93</DiningRating>
  <RoomsRating>3.68</RoomsRating>
  <PropertyType>0</PropertyType>
  <ChainID>92</ChainID>
  <Checkin>14</Checkin>
  <Checkout>12</Checkout>
  <Images>
    <Image>19305754</Image>
    <Image>19305755</Image>
    <Image>19305756</Image>
    <Image>19305757</Image>
    <Image>19305758</Image>
    <Image>19305759</Image>
    <Image>19305760</Image>
    <Image>19305761</Image>
    <Image>19305762</Image>
    <Image>19305763</Image>
    <Image>19305764</Image>
    <Image>19305765</Image>
    <Image>19305766</Image>
    <Image>19305767</Image>
    <Image>37102984</Image>
  </Images>
  <Descriptions>
    <Description>
      <Name>General Description</Name>
      <Value>The Copthorne Aberdeen enjoys a location proximate to several bars, restaurants and other diversions. This Aberdeen hotel is located on the city’s West End, roughly a mile from the many opportunities to engage in sightseeing or simply shopping the day away. The Aberdeen International Airport is approximately 10 miles from the Copthorne Hotel in Aberdeen.

There are 89 rooms in total at the Copthorne Aberdeen Hotel. Each of the is provided with direct-dial telephone service, trouser presses, coffee and tea makers and a private bath with a bathrobe and toiletries courtesy of the hotel. The rooms are light in color.

The Hotel Copthorne Aberdeen offers its guests a restaurant where they can enjoy their meals in a somewhat formal setting. For something more laid-back, guests may have a drink and a light meal in the hotel bar. This hotel does offer business services and there are rooms for meetings located onsite. The hotel also provides a secure parking facility for those who arrive by private car.</Value>
    </Description>
    <Description>
      <Name>LocationDescription</Name>
      <Value>Aberdeen's premier four star hotel located in the city centre just off Union Street and the main business and entertainment areas. Within 10 minutes journey of Aberdeen Railway Station and only 10-20 minutes journey from International Airport.</Value>
    </Description>
  </Descriptions>
</Hotel>

А вот моя программа на Ruby:

require 'rubygems'
require 'nokogiri'
require 'ap'
include Nokogiri

class Hotel < Nokogiri::XML::SAX::Document

    def initialize
        @h = {}
        @h["Images"] = Array.new([])
        @h["Descriptions"] = Array.new([])
        @desc = {}
    end

    def end_document
      ap @h
        puts "Finished..."
    end

    def start_element(element, attributes = [])
        @element = element

    @desc = {} if element == "Description"
    end

    def end_element(element, attributes = [])     
      @h["Images"] << @characters if element == "Image"
    @desc["Name"] = @characters if element == "Name"
    if element == "Value"
      @desc["Value"] = @characters
      @h["Descriptions"] << @desc
    end

    @h[element] = @characters unless %w(Images Image Descriptions Description Hotel Name Value).include? element
    end

    def characters(string)
        @characters = string
    end  
end

# Create a new parser
parser = Nokogiri::XML::SAX::Parser.new(Hotel.new)

# Feed the parser some XML
parser.parse(File.open("/Users/cbmeeks/Projects/shared/data/text/HotelDatabase_EN/00/1040900.xml", 'rb'))

Спасибо

Ответы [ 2 ]

0 голосов
/ 10 сентября 2011

Я столкнулся с подобной проблемой, и вот фактическое объяснение:

def characters(string)
    @characters = string
end

На самом деле должно быть что-то вроде этого:

def start_element(element, attributes = [])     
  #...(other stuff)...

  # Reset/initialize @characters
  @characters = ""
end

def characters(string)
    @characters += string
end

Обоснование состоит в том, что содержимое тега может фактически быть разделено на несколько текстовых узлов, как описано здесь: http://nokogiri.org/Nokogiri/XML/SAX/Document.html

Этот метод может вызываться несколько раз при наличии одной непрерывной строки символов.

Только последний сегмент текстового тела захватывался, потому что каждый раз, когда он сталкивался с текстовым узлом (то есть вызывается метод characters), он заменял содержимое @characters вместо добавления к нему.

0 голосов
/ 07 апреля 2011

Я сократил XML, потому что в нем было много ненужных узлов для решения проблемы.Вот пример того, как я перехожу к тексту:

#!/usr/bin/env ruby
# encoding: UTF-8

xml =<<EOT
<?xml version="1.0" encoding="utf-8"?>
<Hotel>
  <Descriptions>
    <Description>
      <Name>General Description</Name>
      <Value>The Copthorne Aberdeen enjoys a location proximate to several bars, restaurants and other diversions. This Aberdeen hotel is located on the city’s West End, roughly a mile from the many opportunities to engage in sightseeing or simply shopping the day away. The Aberdeen International Airport is approximately 10 miles from the Copthorne Hotel in Aberdeen.

There are 89 rooms in total at the Copthorne Aberdeen Hotel. Each of the is provided with direct-dial telephone service, trouser presses, coffee and tea makers and a private bath with a bathrobe and toiletries courtesy of the hotel. The rooms are light in color.

The Hotel Copthorne Aberdeen offers its guests a restaurant where they can enjoy their meals in a somewhat formal setting. For something more laid-back, guests may have a drink and a light meal in the hotel bar. This hotel does offer business services and there are rooms for meetings located onsite. The hotel also provides a secure parking facility for those who arrive by private car.</Value>
    </Description>
    <Description>
      <Name>LocationDescription</Name>
      <Value>Aberdeen's premier four star hotel located in the city centre just off Union Street and the main business and entertainment areas. Within 10 minutes journey of Aberdeen Railway Station and only 10-20 minutes journey from International Airport.</Value>
    </Description>
  </Descriptions>
</Hotel>
EOT

require 'nokogiri'

doc = Nokogiri::XML(xml)
puts doc.search('Value').map{ |n| n.text }

С примером вывода:

Копторн Абердин расположен недалеко от нескольких баров, ресторанов и других развлечений.,Этот отель в Абердине расположен на западном краю города, примерно в полутора километрах от множества возможностей для осмотра достопримечательностей или просто шоппинга в течение всего дня.Международный аэропорт Абердина находится примерно в 10 милях от отеля Copthorne в Абердине.

В отеле Copthorne Aberdeen всего 89 номеров.В каждом номере есть телефон с прямым набором номера, пресс для брюк, кофеварка и чайник, а также отдельная ванна с халатом и туалетными принадлежностями.Номера светлые.

Отель Copthorne Aberdeen предлагает своим гостям ресторан, где они могут насладиться трапезой в несколько формальной обстановке.Гости могут выпить и перекусить в баре отеля.Этот отель предлагает бизнес-услуги, и есть места для встреч, расположенных на месте.В отеле также есть охраняемая парковка для тех, кто прибывает на личном автомобиле.Первоклассный четырехзвездочный отель Абердина, расположенный в центре города, недалеко от Юнион-стрит и основных деловых и развлекательных районов.В течение 10 минут езды от железнодорожного вокзала Абердина и всего в 10-20 минутах езды от международного аэропорта.

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

Теперь пара вопросов: зачем использовать режим SAX?Входящий XML больше, чем может вписаться в оперативную память вашего хоста?Если нет, используйте DOM, поскольку его гораздо проще использовать.

Когда я запустил его в первый раз, Ruby сказал мне invalid multibyte char (US-ASCII), что означает, что в XML есть что-то, что ему не понравилось.Я исправил это, добавив строку # encoding.Я использую Ruby 1.9.2, что облегчает работу с такими вещами.

Я использую методы доступа CSS для поиска.Nokogiri поддерживает XPath и CSS, так что вы можете потворствовать своим желаниям разбора XML-файла так, как вам хочется.

...