Регулярен израз за съвпадение само с директен подтаг?

Пиша прост RSS анализатор (знам, че има много вече написани) и се натъкнах на проблем. Да кажем, че имам следната RSS емисия:

<channel>
  <title>Sunset Boulevard</title>
  <link>http://www.imdb.com/title/tt0043014/</link>
  <description>A hack screenwriter writes a screenplay..</description>
  <language>English</language>
  <item>
    <rating>8.6</rating>
  </item>
</channel>

Имам метод, който чрез даден таг и подтагове ги извлича в прост хеш. Ето моят "метод":

def extract_text_from_tag(text, tag)
  text =~ /<#{tag}.*?>(?<tag_text>.*?)<\/#{tag}>/m ? $~[:tag_text] : ''
end

За да анализирам канала, първо извличам неговия текст и след това, използвайки масив от предварително дефинирани тагове (заглавие, връзка и т.н.), извличам техните данни. Искам обаче регулярният ми израз да съответства само на директни деца на моя етикет.

Например тук, ако предам етикетите „title“, „link“, „description“, „language“ и „rating“, искам да съпоставя всички тях, с изключение на „rating“ (защото е дете на item).


person Community    schedule 14.02.2013    source източник
comment
Ето защо анализирането на XML с регулярни изрази е трудно. Възможно (за добре дефинирани случаи), но трудно.   -  person Michael Myers    schedule 14.02.2013
comment
Изискване ли е да го правите с regex-es? разрешаването на това с xpath или чрез разбор на dom изглежда по-лесно...   -  person Laur Ivan    schedule 14.02.2013
comment
MichaelMyers - Знам, че е трудно, но форматът е добре дефиниран. equinoxel - Да, задължително е.   -  person    schedule 14.02.2013
comment
Между другото това Руби ли е?   -  person Michael Myers    schedule 14.02.2013
comment
Да, но ме интересува регулярният израз, мога да го преведа в рубинен, ако трябва. :)   -  person    schedule 14.02.2013
comment
Мислех, че може би уточняването на езика ще помогне на разкрасителя на кода да не повреди осветяването за функцията, но очевидно не. Разкрасителят е доста крехък, защото, разберете това, той използва регулярни изрази за анализиране на нерегулярни езици.   -  person Michael Myers    schedule 14.02.2013
comment
Бърз и мръсен подход е да върнете '', ако заснетият текст изглежда, че съдържа етикет -- например, като използвате втори регулярен израз като този: /<\w+>/.   -  person FMc    schedule 14.02.2013
comment
Силно препоръчвам да прочетете RegEx съвпада с отворени тагове с изключение на XHTML self- съдържащи тагове. Той обхваща проблемите с опитите за използване на регулярен израз за анализиране на HTML или XML. Въпреки че може да изглежда забавно да напишете RSS анализатор, наистина трябва да помислите за повторно използване на колело, вместо да измисляте свое собствено. RSS в дивата природа е бъркотия, с няколко спецификации, без ATOM, който също се използва за емисии. Написах такъв, който анализираше всички вариации, обработваше стотици емисии и беше интересно предизвикателство.   -  person the Tin Man    schedule 14.02.2013


Отговори (2)


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

Въпреки това, като контрапример, ето как би изглеждало решение с помощта на Nokogiri:

doc = Nokogiri::XML(rss_xml_string)
doc.xpath('/channel/*').each do |node| # For each child of the root "channel".
  next if node.children.length > 1 # Skip nodes with multiple children.
  puts node.name + ': ' + node.text
end
# title: Sunset Boulevard
# link: http://www.imdb.com/title/tt0043014/
# description: A hack screenwriter writes a screenplay..
# language: English
person maerics    schedule 14.02.2013

С предупреждението, че нещата могат да станат сложни отвъд това, което можете да правите с regex, ето някои предложения:

Вместо .*? можете да използвате [^<>]*?, ако приемем, че "‹" и ">" са екранирани правилно в XML.

Това би предотвратило извличането на съдържанието на item, когато съдържа дъщерен елемент, което може или много да не е желаното поведение (приемам, че това е добре във вашия пример, но може да не е добре като цяло).

Ако все още трябва да извлечете съдържанието на "item" (ако има такъв), с изключение на възможните дъщерни елементи, трябва да използвате условни изрази, които, ако не греша, не се поддържат в Ruby.

Можете да го замените с метод за тестване дали тагът съдържа дъщерен елемент и съответно да приложите регулярен израз, но става доста сложно.

person Sylverdrag    schedule 14.02.2013