XMLDictionary 是一个用于在 iOS 和 Mac OS 上简化 XML 解析和生成的类。XMLDictionary 建立在 NSXMLParser 类之上,但行为更像是一个 DOM 风格的解析器,而不是 SAX 解析器,因为它创建对象的树而不是在每个节点开始和结束时生成事件。
与其他 DOM 解析器不同,XMLDictionary 不会尝试复制 XML 标准的所有细微差别,例如在文本中嵌套标签的能力。如果您需要表示类似 HTML 文档的内容,则 XMLDictionary 不会适用于您。如果您想使用 XML 作为数据交换格式来传递嵌套数据结构,则 XMLDictionary 比其他基于 DOM 的解析器可能提供更简单的解决方案。
注意:“支持”表示已测试过此版本。“兼容”表示库应该运行在这个操作系统版本上(即它不依赖于任何不可用的 SDK 功能),但不再对其进行兼容性测试,可能需要调整或错误修复才能正确运行。
从版本 1.1 开始,XMLDictionary 需要 ARC。如果您希望在非 ARC 项目中使用 XMLDictionary,只需将 -fobjc-arc 编译器标志添加到 XMLDictionary.m 类中。为此,请转到目标设置中的构建阶段选项卡,打开编译源代码组,双击列表中的 XMLDictionary.m,然后在弹出窗口中输入 -fobjc-arc。
如果您想将整个项目转换为 ARC,请取消注释 XMLDictionary.m 中的 #error 行,然后在 Xcode 中运行“编辑 > 重构 > 转换为 Objective-C ARC...”工具,确保所有要使用 ARC 的文件都已选中(包括 XMLDictionary.m)。
XMLDictionary 的方法都应该是线程安全的。可以在不同的线程上并发使用多个 XMLDictionaryParsers,但不可在多个线程上并发调用相同的解析器。
要在一个应用中使用 XMLDictionary,只需将类文件拖放到您的项目中。
XMLDictionaryParser 类负责将 XML 文件解析为字典。通常不需要显式使用此类,因为可以使用添加到 NSDictionary 的实用方法,但如果您想修改默认解析器设置,则可能非常有用。
如果您需要为不同的字典使用不同的设置,则可以创建 XMLDictionaryParser 的新实例。一旦创建了 XMLDictionaryParser,您就可以使用以下方法使用该特定的解析器实例解析 XML 文件
- (NSDictionary *)dictionaryWithData:(NSData *)data;
- (NSDictionary *)dictionaryWithString:(NSString *)string;
- (NSDictionary *)dictionaryWithFile:(NSString *)path;
- (NSDictionary *)dictionaryWithParser:(NSXMLParser *)parser;
或者,您可以直接修改 [XMLDictionaryParser sharedInstance]
的设置,以影响后续使用 NSDictionary 类扩展方法解析的所有字典的设置。
使用以下属性来调整解析行为
@property (nonatomic, assign) BOOL collapseTextNodes;
如果为 YES(默认值),则只包含文本且没有任何子元素、属性或注释的标签将被折叠成一个字符串对象,简化了对象树的遍历。
@property (nonatomic, assign) BOOL stripEmptyNodes;
如果为 YES(默认值),则空的标签(没有任何子元素、属性、文本或注释)将被移除。
@property (nonatomic, assign) BOOL trimWhiteSpace;
如果为 YES(默认值),将从文本节点中去除前导和尾随空白,并且仅包含空白的文本节点将从字典中省略。
@property (nonatomic, assign) BOOL alwaysUseArrays;
如果为 YES
,则每个子节点都将表示为一个数组,即使只有一个子节点也是如此。这简化了对可能重复的属性所需的逻辑,因为您不需要使用 [value isKindOfClass:[NSArray class]]
来检查单个情况。默认为 NO
。
@property (nonatomic, assign) BOOL preserveComments;
如果为 YES
,XML 注释将组合成一个名为 __comments
的数组,可以通过 comments
方法访问。默认为 NO
。
@property (nonatomic, assign) XMLDictionaryAttributesMode attributesMode;
此属性控制如何处理 XML 属性。默认值是 XMLDictionaryAttributesModePrefixed
,意味着属性将被包含在字典中,并以 _(下划线)前缀开头,以避免命名空间冲突。其他值包括 XMLDictionaryAttributesModeDictionary
,该值将所有属性放在一个单独的字典中,XMLDictionaryAttributesModeUnprefixed
,该值将属性不使用前缀(这可能导致与节点的冲突)包含在内,以及 XMLDictionaryAttributesModeDiscard
,该值将移除属性。
@property (nonatomic, assign) XMLDictionaryNodeNameMode nodeNameMode;
此属性控制节点名称的处理方式。默认值是 XMLDictionaryNodeNameModeRootOnly
,意味着节点名称将仅包含在根字典中(子名称可以从中字典键推断,但 nodeName
方法除了根节点外不适用)。其他值包括 XMLDictionaryNodeNameModeAlways
,该值表示节点名称将包含在字典中并以 __name
为键(可以使用 nodeName
方法访问),或 XMLDictionaryNodeNameModeNever
,该值表示永远不会包含 `__name' 键。
XMLDictionary 以以下方法扩展 NSDictionary
从现有的 NSXMLParser 创建新的 NSDictionary 对象。当通过 AFNetworking 获取数据时非常有用。
+ (NSDictionary *)dictionaryWithXMLData:(NSData *)data;
从 XML 编码的数据创建新的 NSDictionary 对象。
+ (NSDictionary *)dictionaryWithXMLString:(NSString *)string;
从 XML 编码的字符串创建新的 NSDictionary 对象。
+ (NSDictionary *)dictionaryWithXMLFile:(NSString *)path;
从 XML 编码的文件创建新的 NSDictionary 对象。
- (NSString *)attributeForKey:(NSString *)key;
获取给定键的 XML 属性(键名不应包含前缀)。
- (NSDictionary *)attributes;
获取给定节点字典的所有 XML 属性的字典。如果节点没有属性,则此方法将返回 nil。
- (NSDictionary *)childNodes;
获取给定节点字典的所有子节点的字典。如果有多个节点具有相同的名称,则它们将被组合成一个数组。如果节点没有子节点,则此方法将返回 nil。
- (NSArray *)comments;
获取给定节点的所有评论的数组。请注意,相对于其他节点的嵌套不会 preserved。如果节点没有评论,则返回 nil。
- (NSString *)nodeName;
获取节点的名称。如果名称未知,则返回 nil。
- (NSString *)innerText;
获取节点的文本内容。如果节点没有文本内容,则返回 nil:
- (NSString *)innerXML;
以 XML 编码的字符串形式获取节点的内设内容。该 XML 字符串将不包括容器节点本身。
- (NSString *)XMLString;
以 XML 编码的字符串形式获取节点及其内容。如果节点名称未知,顶层标签将为 <root>
。
- (NSArray *)arrayValueForKeyPath:(NSString *)keyPath;
功能与 valueForKeyPath:
相同,但返回的值始终是数组。所以如果有单个值,将以 @[value]
的形式返回。
- (NSString *)stringValueForKeyPath:(NSString *)keyPath;
功能与 valueForKeyPath:
相同,但返回的值始终是字符串。所以如果值是字典,将返回 innerText
的文本值,如果值是数组,则返回第一个元素。
- (NSDictionary *)dictionaryValueForKeyPath:(NSString *)keyPath;
功能与 valueForKeyPath:
相同,但返回的值始终是字典。所以如果启用 collapseTextNodes 选项,并且值是字符串,则在返回之前将其转换为字典,如果值是数组,则返回第一个元素。
加载 XML 文件的最简单方法是以下方法
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"someFile" ofType:@"xml"];
NSDictionary *xmlDoc = [NSDictionary dictionaryWithXMLFile:filePath];
然后您可以根据其他对象树(例如从 Plist 加载的对象树)的方式遍历字典。
要访问嵌套节点和属性,您可以使用 valueForKeyPath 语法。例如,要从以下 XML 中获取 <foo>
的字符串值
<root>
<bar cliche="true">
<foo>Hello World</foo>
</bar>
<banjo>Was his name-oh</banjo>
</root>
您将编写如下:
NSString *foo = [xmlDoc valueForKeyPath:@"bar.foo"];
上面的例子假定您正在使用 collapseTextNodes
和 alwaysUseArrays
的默认设置。如果禁用 collapseTextNodes
,您将使用以下方法编写来访问 <foo>
的值:
NSString *foo = [[xmlDoc valueForKeyPath:@"bar.foo"] innerText];
如果启用 alwaysUseArrays
选项,您将使用以下之一,具体取决于 collapseTextNodes
属性
NSString *foo = [[xmlDoc valueForKeyPath:@"bar.foo"] firstObject];
NSString *foo = [[[xmlDoc valueForKeyPath:@"bar.foo"] firstObject] innerText];
要获取 bar
的 cliché 属性,可以编写如下:
NSString *barCliche = [xmlDoc[@"bar] attributes][@"cliche"];
如果 attributesMode
的设置是默认值 XMLDictionaryAttributesModePrefixed
,则也可以这样做
NSString *barCliche = [xmlDoc valueForKeyPath:@"bar._cliche"];
如果它设置为 XMLDictionaryAttributesModeUnprefixed
,则可以这样做
NSString *barCliche = [xmlDoc valueForKeyPath:@"bar.cliche"];
版本 1.4
版本 1.3
版本 1.2.2
版本 1.2.1
版本 1.2
__name
和 __coment
键不再默认包含'
attributeForKey:
方法版本 1.1
版本 1.0