Разрешение объектов HTML с NSXMLParser на iPhone

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

У меня есть веб-страница HTML, которая не находится под моим контролем, и я должен проанализировать его из своего приложения для iPhone. Здесь это - образец веб-страницы, о которой я говорю:

<HTML>
  <HEAD>
    <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  </HEAD>
  <BODY>
    <LI class="bye bye" rel="hello 1">
      <H5 class="onlytext">
        <A name="morning_part">morning</A>
      </H5>
      <DIV class="mydiv">
        <SPAN class="myclass">something about you</SPAN> 
        <SPAN class="anotherclass">
          <A href="http://www.google.it">Bye Bye &egrave; un saluto</A>
        </SPAN>
      </DIV>
    </LI>
  </BODY>
</HTML>

Я использую NSXMLParser, и он не подходит до него, находят è объект HTML. Это называет foundCharacters: для "До свидания" и затем это называет resolveExternalEntityName:systemID:: с entityName "egrave". В этом методе я просто возвращаю символ "è" trasformed в NSData, foundCharacters называют, снова добавляя строку "è" к предыдущей "До свидания", и затем синтаксический анализатор повышает ошибку NSXMLParserUndeclaredEntityError.

У меня нет DTD, и я не могу изменить файл HTML, который я анализирую. У Вас есть какие-либо идеи об этой проблеме? Заранее спасибо всем Вам, Rob.

Обновление (12/03/2010). После предложения Griffo я закончил с чем-то вроде этого:

data = [self replaceHtmlEntities:data];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser parse];

где replaceHtmlEntities: (NSData *), что-то вроде этого:

- (NSData *)replaceHtmlEntities:(NSData *)data {

    NSString *htmlCode = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding];
    NSMutableString *temp = [NSMutableString stringWithString:htmlCode];

    [temp replaceOccurrencesOfString:@"&amp;" withString:@"&" options:NSLiteralSearch range:NSMakeRange(0, [temp length])];
    [temp replaceOccurrencesOfString:@"&nbsp;" withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [temp length])];
    ...
    [temp replaceOccurrencesOfString:@"&Agrave;" withString:@"À" options:NSLiteralSearch range:NSMakeRange(0, [temp length])];

    NSData *finalData = [temp dataUsingEncoding:NSISOLatin1StringEncoding];
    return finalData;

}

Но я все еще смотрю лучший способ решить эту проблему. Я попробую TouchXml в следующие дни, но я все еще думаю, что должен быть способ сделать это использование NSXMLParser API, поэтому если Вы знаете, как, не стесняйтесь писать это здесь :)

15
задан Mike Abdullah 21 February 2011 в 12:42
поделиться

4 ответа

После изучения нескольких альтернатив выяснилось, что NSXMLParser не поддерживает сущности, отличные от стандартных сущностей <, >, ', " и &

Приведенный ниже код не работает, что приводит к NSXMLParserUndeclaredEntityError.


// Create a dictionary to hold the entities and NSString equivalents
// A complete list of entities and unicode values is described in the HTML DTD
// which is available for download http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent


NSDictionary *entityMap = [NSDictionary dictionaryWithObjectsAndKeys: 
                     [NSString stringWithFormat:@"%C", 0x00E8], @"egrave",
                     [NSString stringWithFormat:@"%C", 0x00E0], @"agrave", 
                     ...
                     ,nil];

NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser setShouldResolveExternalEntities:YES];
[parser parse];

// NSXMLParser delegate method
- (NSData *)parser:(NSXMLParser *)parser resolveExternalEntityName:(NSString *)entityName systemID:(NSString *)systemID {
    return [[entityMap objectForKey:entityName] dataUsingEncoding: NSUTF8StringEncoding];
}

Попытки объявить сущности, дополнив HTML-документ объявлениями ENTITY, проходят, однако расширенные сущности не передаются обратно в parser:foundCharacters и символы è и à отбрасываются.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
[
  <!ENTITY agrave "à">
  <!ENTITY egrave "è">
]>

В другом эксперименте я создал полностью валидный xml документ с внутренним DTD

<?xml version="1.0" standalone="yes" ?>
<!DOCTYPE author [
    <!ELEMENT author (#PCDATA)>
    <!ENTITY js "Jo Smith">
]>
<author>&lt; &js; &gt;</author>

Я реализовал метод делегата parser:foundInternalEntityDeclarationWithName:value:; и ясно, что парсер получает данные о сущностях, однако parser:foundCharacters вызывается только для предварительно определенных сущностей.

2010-03-20 12:53:59.871 xmlParsing[1012:207] Parser Did Start Document
2010-03-20 12:53:59.873 xmlParsing[1012:207] Parser foundElementDeclarationWithName: author model: 
2010-03-20 12:53:59.873 xmlParsing[1012:207] Parser foundInternalEntityDeclarationWithName: js value: Jo Smith
2010-03-20 12:53:59.874 xmlParsing[1012:207] didStartElement: author type: (null)
2010-03-20 12:53:59.875 xmlParsing[1012:207] parser foundCharacters Before: 
2010-03-20 12:53:59.875 xmlParsing[1012:207] parser foundCharacters After: <
2010-03-20 12:53:59.876 xmlParsing[1012:207] parser foundCharacters Before: <
2010-03-20 12:53:59.876 xmlParsing[1012:207] parser foundCharacters After: < 
2010-03-20 12:53:59.877 xmlParsing[1012:207] parser foundCharacters Before: < 
2010-03-20 12:53:59.878 xmlParsing[1012:207] parser foundCharacters After: <  
2010-03-20 12:53:59.879 xmlParsing[1012:207] parser foundCharacters Before: <  
2010-03-20 12:53:59.879 xmlParsing[1012:207] parser foundCharacters After: <  >
2010-03-20 12:53:59.880 xmlParsing[1012:207] didEndElement: author with content: <  >
2010-03-20 12:53:59.880 xmlParsing[1012:207] Parser Did End Document

Я нашел ссылку на учебник по использованию SAX интерфейса LibXML. xmlSAXHandler, который используется NSXMLParser, позволяет определить обратный вызов getEntity. После вызова getEntity расширение сущности передается обратному вызову characters.

NSXMLParser здесь не хватает функциональности. Должно происходить так: NSXMLParser или его делегат хранит определения сущностей и передает их обратному вызову xmlSAXHandler getEntity. Этого явно не происходит. Я напишу сообщение об ошибке.

Тем временем, предыдущий ответ о выполнении замены строки вполне приемлем, если ваши документы маленькие. Посмотрите учебник по SAX, упомянутый выше, а также пример приложения XMLPerformance от Apple, чтобы понять, стоит ли реализовывать парсер libxml самостоятельно.

Это было весело.

9
ответ дан 1 December 2019 в 04:58
поделиться

Вы можете выполнить замену строки в данных перед их разбором с помощью NSXMLParser. Насколько я знаю, NSXMLParser работает только с UTF-8.

0
ответ дан 1 December 2019 в 04:58
поделиться

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

0
ответ дан 1 December 2019 в 04:58
поделиться

Я думаю, вы столкнетесь с другой проблемой с этим примером, поскольку это не действующий XML, который ищет NSXMLParser.

Проблема в том, что теги META, LI, HTML и BODY не закрыты, поэтому синтаксический анализатор полностью просматривает остальную часть документа в поисках закрывающего тега.

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

0
ответ дан 1 December 2019 в 04:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: