Разбор XHTML со встроенными тегами

Я пытаюсь разобрать XHTML-документ с помощью TBXML на iPhone (хотя я был бы рад использовать либо libxml2, либо NSXMLParser, если бы это было проще). Мне нужно извлечь содержимое тела в виде серии абзацев и сохранить встроенные теги, например:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
       <title>Title</title>
       <link rel="stylesheet" href="css/style.css" type="text/css"/>
       <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8"/>
    </head>
    <body>
       <div class="body">
          <div>
             <h3>Title</h3>
             <p>Paragraph with <em>inline</em> tags</p>
             <img src="image.png" />
          </div>
       </div>
    </body>
</html>

Мне нужно извлечь абзац, но сохранить содержимое <em>inline</em> с абзацем, все мои тесты до сих пор извлекали его как подэлемент, и я точно не знал, где он помещается в абзаце.

Может ли кто-нибудь предложить способ сделать это?

Спасибо.


person JWood    schedule 16.04.2010    source источник
comment
Извиняюсь за форматирование, пытался отредактировать, но почему-то выдает ошибку.   -  person JWood    schedule 16.04.2010
comment
user290796: Потому что вы пытались использовать встроенный шрифт кода там, где вам нужно было использовать блок кода. См. daringfireball.net/projects/markdown/syntax .   -  person Peter Hosey    schedule 16.04.2010


Ответы (1)


Предположение 1. Вас интересуют только данные в элементе p (абзац) и то, что вы используете NSXMLParser.

Предположение 2. Вы хотите сохранить любой элемент внутри p нетронутым.

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

Настройте NSXMLParser delegate, используя пример кода от Apple. Вашему делегату потребуется ivar BOOL inParagraph для отслеживания, когда данные будут сохранены или удалены. Начальное значение inParagaph равно NO. Когда ваш делегат получит сообщение parser:didStartElement:namespaceURI:qualifiedName:attributes:, if ([element isEqual:@"p"]) очистите переменную receivedData и установите inParagraph = YES

РЕДАКТИРОВАТЬ: полученные данные являются NSMutableString. Исправлены примеры кода

В этот момент ваш parser delegate хочет сохранить полученные данные.

Когда parser delegate получит сообщение parser:foundCharacters:, добавьте строку к receivedData, как в примере кода.

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    if (inParagraph) [receivedData appendString:string];
}

Когда синтаксический анализатор встречает встроенный элемент, делегат снова получит parser:didStartElement:namespaceURI:qualifiedName:attributes:. Это когда переменная состояния inParagraph важна. Парсер не будет получать закрывающие символы '‹' и '>' элемента, поэтому вам придется обернуть elementName в символы '‹' и '>' и добавить к receivedData. Что-то типа

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{ if (inParagraph) 
    {
        NSString *inlineElementName = [NSString stringWithFormat:@"<%@>", elementName];
        [receivedData appendString:inlineElementName];
    }
....
}

Когда parser delegate получает сообщение parser:didEndElement:namespaceURI:qualifiedName:, он проверяет, находится ли оно в элементе "p", if (inParagraph && ![elementName isEqual:@"p"], закрывает встроенный элемент. if ([elementName isEqual:@"p"]) добавьте содержимое receivedData к NSMutableArray, содержащему ваши абзацы.

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
   if (inParagraph)
        {
             if (![elementName isEqual:@"p"])
                 { 
                      NSString *inlineElementName = [NSString stringWithFormat:@"</%@>", elementName];
                     [receivedData appendString:inlineElementName];             
                 } else { // received closing </p> tag add receivedData to the paragraph array
                          [paragraphsArray addObject:[receivedData copy]];
                          [self setInParagraph:NO];
                         }
                 }
       }
}
person falconcreek    schedule 17.04.2010
comment
Это было именно то, что я искал! Спасибо! - person JWood; 22.04.2010