Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在iPhone上使用NSXMLParser解析html实体_Iphone_Parsing_Nsxmlparser_Html Entities - Fatal编程技术网

在iPhone上使用NSXMLParser解析html实体

在iPhone上使用NSXMLParser解析html实体,iphone,parsing,nsxmlparser,html-entities,Iphone,Parsing,Nsxmlparser,Html Entities,我想我读了每一个关于这个问题的网页,但我仍然找不到解决办法,所以我来了 我有一个HTML网页,它不在我的控制之下,我需要从我的iPhone应用程序中解析它。以下是我正在谈论的网页示例: <HTML> <HEAD> <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> </HEAD> <BODY

我想我读了每一个关于这个问题的网页,但我仍然找不到解决办法,所以我来了

我有一个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>
其中replaceThMLentities:(NSData*)是这样的:

data = [self replaceHtmlEntities:data];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser parse];
- (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来实现这一点的方法,因此,如果您知道如何实现,请随意在这里编写。

在使用NSXMLParser解析数据之前,您可以在数据中进行字符串替换。据我所知,NSXMLParser是UTF-8。

我认为您将在这个示例中遇到另一个问题,因为它不是NSXMLParser所寻找的有效XML

上面提到的确切问题是,标记META、LI、HTML和BODY没有关闭,因此解析器会在文档的其余部分查找关闭标记


如果您没有权限更改HTML,我所知道的唯一解决方法就是使用插入的结束标记对其进行镜像。

我会尝试使用不同的解析器,如libxml2-理论上我认为应该能够处理糟糕的HTML。

在探索了几种替代方法之后,NSXMLParser似乎不支持标准实体
,&apos;以外的实体;,“和&;

下面的代码失败,导致出现
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文档前面添加实体声明来声明实体的尝试将通过,但是扩展的实体不会传递回
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 "è">
]>
我找到了关于的教程的链接。
NSXMLParser
使用的
xmlSAXHandler
允许定义
getEntity
回调。调用
getEntity
后,实体的扩展将传递给
字符
回调

NSXMLParser
在这里缺少功能。应该发生的是
NSXMLParser
或其
委托
存储实体定义并将其提供给
xmlSAXHandler
getEntity回调。这显然没有发生。我将提交错误报告

同时,如果您的文档很小,那么执行字符串替换的早期答案是完全可以接受的。请查看上面提到的SAX教程以及Apple的XMLPerformance示例应用程序,看看自己实现
libxml
解析器是否值得


这很有趣。

因为我刚开始做iOS开发,所以我一直在搜索同样的东西,并找到了一个相关的邮件列表条目:


这与您最初的解决方案非常相似,也会导致解析器错误NSXMLParserErrorDomain error 26;但之后它会继续解析。当然,问题是更难区分真正的错误;-)

一个可能的更少的黑客解决方案是用本地修改的DTD替换DTD,并使用ll外部实体声明替换为本地实体声明

我就是这样做的:

首先,查找文档DTD声明并将其替换为本地文件。例如,替换为:

<!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>
打开DTD文件,查找任何外部实体引用:

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

%HTMLAT1;
将其替换为实体文件的内容(在上述情况下)


替换所有外部引用后,NSXMLParser应该正确处理实体,而无需在每次解析XML文件时下载每个远程DTD/外部实体。

Ps。我知道NSXMLParser是XML解析器,而不是HTML解析器,但我了解到libxml2也存在同样的问题。NSXMLParser似乎更容易处理比libxml2强,所以我首先尝试了这个,希望它能工作。如果没有解决方案,那么我将不得不切换到libxml2…正如下面Griffo所建议的,我用适当的字符替换了文本中的每个html实体,然后用NSXMLParser对其进行解析。现在它可以工作了,但我真的想知道哪一个更好呃,这是解决这类问题的一种方法。我注意到,对于符号和字符“&”的&;实体,至少对于多个“foundcharacter”“电话,处理起来很痛苦。是的,我只是在想这件事,但我不能真的认为这是一个真正的解决办法。。。因为有一个方法resolveExternalEntityName:systemID,文档中说:“委托可以解析外部实体(例如,定位和读取外部声明的DTD),并将结果作为NSData对象提供给解析器对象。”因此,它应该存在一种使用它来解析实体并将其转换为解析器的方法。。。可能我在NSXMLParser的逻辑中遗漏了一些东西……但我读到NSXMLDocument不可用于iphone开发,是真的吗?NSXMLDocument在TouchXML中可用。看这里:谢谢,我一定会试试的。但我不能停止思考,什么是正确的方式来处理这个案件只使用sdk代码…对不起。。。示例中的html代码只是文件的第一部分。那是我的错。该文件的每个标记都已正确关闭。我了解到libxml2有一个HTMLparser,但我找不到关于这个的教程、文档或示例,这就是我第一次尝试NSXMLParser的原因。:(这不起作用。它继续引发NSXMLParserUndeclaredEntityError=26.)(我使用了您自己的代码。它输入了resolveExternalEntityName方法,然后引发异常…您可以包含url吗?我还有另一个理论要测试。仍在寻找解决方案。找到了一个可能的答案,但它无法帮助我们。)
- (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];
}
<!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>
<!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>
NSBundle* bundle = [NSBundle bundleForClass:[self class]];
NSString* path = [[bundle URLForResource:@"xhtml1-transitional" withExtension:@"dtd"] absoluteString];
<!ENTITY % HTMLlat1 PUBLIC
   "-//W3C//ENTITIES Latin 1 for XHTML//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
%HTMLlat1;