2013-02-14 3 views
0

Я пишу простой синтаксический анализатор RSS (я знаю, что многие уже написаны), и я наткнулся на проблему. Скажем, у меня есть следующий RSS канал:Регулярное выражение для соответствия только прямой subtag?

<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' (потому что это дочерний элемент пункт).

+0

Вот почему синтаксический анализ XML с помощью регулярных выражений. Возможно (для четко определенных случаев), но сложно. –

+2

Требуется ли это делать с регулярными выражениями? решить это с помощью xpath или с помощью синтаксического анализа дома проще ... –

+0

MichaelMyers - Я знаю, что это сложно, но формат четко определен. equinoxel - Да, это требование. – 2013-02-14 15:18:56

ответ

1

Я вижу из комментариев, что вы должны анализировать этот канал 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 
0

С оговоркой, что все может усложниться за то, что вы можете сделать с регулярным выражением, вот несколько советов:

Вместо .*? вы можете использовать [^<>]*?, считая, что «<» и «>» правильно экранированы в XML.

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

Если вам все равно нужно извлечь содержимое «item» (если есть), за исключением возможных дочерних элементов, вам нужно использовать условные операторы, которые, если не ошибаюсь, не поддерживаются в Ruby.

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

Смежные вопросы