Frage

Ich glaube, ich jede einzelne Web-Seite zu lesen dieses Problem im Zusammenhang, aber ich kann immer noch keine Lösung für sie finden, so bin ich hier.

Ich habe eine HTML-Webseite Weicht nicht unter meiner Kontrolle ist und ich brauche es von meiner iPhone-Anwendung zu analysieren. Hier ist ein Beispiel der Web-Seite ich spreche:

<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>

Ich verwende NSXMLParser und es geht gut, bis es die finden è html Einheit. Er fordert Foundcharacters: für "Bye Bye" und dann nennt es resolveExternalEntityName: SystemID :: mit einem entityName von "egrave". Bei diesem Verfahren bin Rückkehr i nur das Zeichen „è“ trasformed in einem NSData, die Foundcharacters erneut aufgerufen wird die Zeichenfolge „è“ zur vorherigen „Bye Bye“ hinzufügen und dann der Parser Erhöhung der NSXMLParserUndeclaredEntityError Fehler.

ich keine DTD haben, und ich kann nicht die HTML-Datei ändern, ich bin Parsen. Haben Sie Ideen zu diesem Problem? Vielen Dank im Voraus an alle von euch, Rob.

Update (12.03.2010) . Nach dem Vorschlag von Griffo endete ich mit so etwas wie dies oben:

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

Dabei gilt replaceHtmlEntities: (NSData *) so etwas wie dieses:

- (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;

}

Aber ich suche immer noch den besten Weg, um dieses Problem zu lösen. Ich werde versuchen, TouchXML in den nächsten Tagen, aber ich denke immer noch, dass es einen Weg geben, sollten diese mit NSXMLParser API zu tun, wenn Sie also wissen, wie fühlen Sie sich frei, es zu schreiben hier:)

War es hilfreich?

Lösung

Nach mehreren Alternativen zu erforschen, scheint es, dass NSXMLParser nicht andere Stellen als die Standard-Entitäten unterstützt &lt;, &gt;, &apos;, &quot; and &amp;

Der folgende Code schlägt in einem NSXMLParserUndeclaredEntityError führt.


// 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];
}

Versuche, die Einheiten zu erklären, durch das HTML-Dokument mit ENTITY Erklärungen vorangestellt werden vergehen, aber die erweiterten Unternehmen nicht zurück an parser:foundCharacters und die E und A Zeichen fallen gelassen werden.

<?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 "è">
]>

In einem anderen Experiment habe ich ein völlig gültiges XML-Dokument mit einer internen DTD

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

ich die parser:foundInternalEntityDeclarationWithName:value:; Delegatmethode implementiert und es ist klar, dass der Parser die Entität Daten erhält, aber die parser:foundCharacters nur für die vordefinierten Entitäten genannt wird.

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

fand ich einen Link zu einem Tutorial auf die SAX-Schnittstelle verwenden von LibXML . Die xmlSAXHandler, die von NSXMLParser verwendet wird ermöglicht ein getEntity Rückruf definiert werden. Nach dem Aufruf von getEntity, die Expansion des Unternehmens an dem characters Rückruf übergeben.

NSXMLParser fehlt hier Funktionalität. Was soll passieren, dass die NSXMLParser oder seine delegate speichern die Entitätsdefinitionen und sie an die Callback xmlSAXHandler getEntity bieten. Dies geschieht offensichtlich nicht. Ich werde einen Fehlerbericht.

In der Zwischenzeit die frühere Antwort von einem String Ersatz Durchführung ist durchaus akzeptabel, wenn Ihre Dokumente klein sind. Schauen Sie sich die SAX-Tutorial oben zusammen mit der XMLPerformance Beispielanwendung von Apple erwähnt, um zu sehen, ob der Umsetzung des libxml Parsers auf eigener Faust lohnt.

Das hat Spaß gemacht.

Andere Tipps

Eine möglicherweise weniger Hacky Lösung ist die DTD mit einem lokalen modifizierten einem mit allen externen Entitätsdeklaration ersetzen mit lokalen ersetzt.

Dies ist, wie ich es tun:

Zuerst finden und das Dokument DTD-Deklaration mit einer lokalen Datei ersetzen Ersetzen Sie beispielsweise diese:.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html><body><a href='a.html'>hi!</a><br><p>Hello</p></body></html>

mit dieser:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "file://localhost/Users/siuying/Library/Application%20Support/iPhone%20Simulator/6.1/Applications/17065C0F-6754-4AD0-A1EA-9373F6476F8F/App.app/xhtml1-transitional.dtd">
<html><body><a href='a.html'>hi!</a><br><p>Hello</p></body></html>

`` `

Laden Sie die DTD von der W3C-URL und fügen Sie es zu Ihrem App Bundle Sie können den Pfad der Datei mit folgenden Code finden.

NSBundle* bundle = [NSBundle bundleForClass:[self class]];
NSString* path = [[bundle URLForResource:@"xhtml1-transitional" withExtension:@"dtd"] absoluteString];

Öffnen Sie die DTD-Datei , finden Sie externe Entity-Referenz:

<!ENTITY % HTMLlat1 PUBLIC
   "-//W3C//ENTITIES Latin 1 for XHTML//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
%HTMLlat1;      

ersetzen Sie es mit dem Inhalt der Entity-Datei ( http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent im obigen Fall)

Nachdem alle externen Referenz zu ersetzen, NSXMLParser sollte richtig die Entitäten handhaben, ohne die Notwendigkeit, jeden Remote-DTD / externen Entitäten jedes Mal zum Download es eine XML-Datei analysieren.

Sie können innerhalb der Daten eine Zeichenfolge ersetzen, bevor Sie es mit NSXMLParser analysieren. NSXMLParser ist UTF-8 nur soweit ich weiß.

Ich glaube, Sie gehen in ein anderes Problem bei diesem Beispiel laufen, da es nicht vaild XML ist das, was die NSXMLParser für zuschauen.

Das genaue Problem in der oben ist, dass die Tags META, LI, HTML und BODY geschlossen sind nicht so der Parser alle so aussieht, obwohl der Rest des Dokuments für seinen End-Tag sucht.

Der einzige Weg, um dieses, die ich kenne, wenn Sie Zugang haben nicht die HTML zu ändern, ist es eingefügt mit den schließenden Tags zu spiegeln.

Ich würde versuchen, einen anderen Parser verwenden, wie libxml2 - in der Theorie denke ich, dass man in der Lage sein sollte, eine schlechte HTML umgehen

.

Da ich gerade angefangen habe iOS Entwicklung zu tun Ich habe für die gleiche Sache der Suche und fand einen ähnlichen Mailinglisteneintrag: http://www.mail-archive.com/cocoa-dev@lists.apple.com/msg17706.html

- (NSData *)parser:(NSXMLParser *)parser resolveExternalEntityName: (NSString *)entityName systemID:(NSString *)systemID {       
    NSAttributedString *entityString = [[[NSAttributedString alloc] initWithHTML:[[NSString stringWithFormat:@"&%@;", entityName] dataUsingEncoding:NSUTF8StringEncoding] documentAttributes:NULL] autorelease];

    NSLog(@"resolved entity name: %@", [entityString string]);

    return [[entityString string] dataUsingEncoding:NSUTF8StringEncoding];
}

Das ist ziemlich ähnlich wie Ihre ursprüngliche Lösung und verursacht auch ein Parser-Fehler NSXMLParserErrorDomain error 26; aber es funktioniert auch nach, dass das Parsen. Das Problem ist natürlich, dass es schwieriger ist, abgesehen wirkliche Fehler zu sagen; -)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top