BRCybertron - セイバートロン
BRCybertron 是一个用于执行 XSLT 1.0 转换的 Objective-C 框架。它作为一个轻量级的包装器实现,围绕 libxslt 和 libxml。
BRCybertron 已经设计用于在 iOS 上运行,iOS 不提供 libxslt
。因此,libxslt
(版本 1.1.29)被静态编译进 BRCybertron 中。项目的目标是让用户保持在美好的 Objective-C 世界中,而无需深入到 libxslt/xml
C API。
机器人 伪装文档
以下是一个使用内存中 XML 和 XSLT 资源执行 XSLT 转换的例子
id<CYInputSource> input = [[CYDataInputSource alloc] initWithData:
[@"<input><msg>Hello, BRCybertron.</msg></input>" dataUsingEncoding:NSUTF8StringEncoding]
options:CYParsingDefaultOptions];
CYTemplate *xslt = [CYTemplate templateWithData:
[@"<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' "
@"xmlns:xs='http://www.w3.org/2001/XMLSchema' "
@"exclude-result-prefixes='xs' version='1.0'>"
@"<xsl:output method='xml' encoding='UTF-8' />"
@"<xsl:template match='input'>"
@"<output>"
@"<msg><xsl:value-of select='msg'/></msg>"
@"<msg>More than meets the eye!</msg>"
@"</output>"
@"</xsl:template>"
@"</xsl:stylesheet>"
dataUsingEncoding:NSUTF8StringEncoding]];
// run transform, and return results as an XML string
NSString *result = [xslt transformToString:input parameters:nil error:nil];
此时,result
包含如下 XML
<?xml version="1.0" encoding="UTF-8"?>
<output>
<msg>Hello, BRCybertron.</msg>
<msg>More than meets the eye!</msg>
</output>
XML 解析
任何XSLT工作流的大多数部分都涉及解析XML。XSLT转换的输入不仅是以XML格式提供的,而且XSLT语言本身也基于XML。BRCybertron包括通过对CYInputSource API进行解析支持解析XML文档,并提供CYDataInputSource以解析存储在内存中的XML(通过NSData
对象)以及CYFileInputSource,以便从文件中解析XML。
XSLT转换
类CYTemplate
代表一个已解析且可重用的XSLT文档。您可以从NSData
对象
// create from NSData instance
NSData *xsltData = ...;
CYTemplate *xslt = [CYTemplate templateWithData:xsltData];
或从文件创建实例
// create from a file
NSString *pathToXsltFile = ...;
CYTemplate *xslt = [CYTemplate templateWithContentsOfFile:pathToXsltFile];
一旦您有了模板实例,您可以通过将其转换成字符串或文件来运行多个转换,以符合您的需求
id<CYInputSource> xml = ...;
NSError *error = nil;
NSString *result = [xslt transformToString:xml parameters:nil error:&error];
或将其转换为文件
id<CYInputSource> xml = ...;
NSString *pathToOutputFile = ...;
NSError *error = nil;
[xslt transform:xml parameters:nil toFile:pathToOutputFile error:&error];
XSLT参数
您可以将字符串参数传递到转换中,这些参数将在XSLT文档中表示为顶层<xsl:param>
元素。只需将字典传递给transform*
方法,其中键是要传递的参数的名称。例如,在以下XSLT中
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs xml"
version="1.0">
<xsl:output method="html" version="5.0" encoding="UTF-8" indent="yes" />
<xsl:param name="first-name"/>
<xsl:template match="passage">
<html>
<body>
<p>Hello, <xsl:value-of select="$first-name"/>.</p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
我们可以这样传递一个first-name
参数
id<CYInputSource> xml = ...;
NSError *error = nil;
NSString *result = [xslt transformToString:xml parameters:@{ @"first-name" : @"Bob" } error:&error];
并且(给定适当的输入XML)会转换成
<html>
<body>
<p>Hello, Bob.</p>
</body>
</html>
xsl:import 和 xsl:include 支持
当使用基于文件的XSL文档时,使用相对URL的xsl:import
和xsl:include
语句将按预期工作。然而,当使用CYDataInputSource
时,您可以提供一个显式的基URL来从其中解析相对URL。例如,您可以配置基路径为应用主bundle中的虚拟文件,如下所示
// obtain XSL as data from somewhere...
NSData *xslData = nil;
// create a base path to a virtual file named "data.xml" within the app bundle
NSString *basePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"data.xml"];
CYDataInputSource *xsl = [[CYDataInputSource alloc] initWithData:xslData basePath:basePath options:0];
// create templates instance
CYTemplate *tmpl = [[CYTemplate alloc] initWithInputSource:xsl];
更普遍的是,您可以使用CYInputSourceResolver
API来根据需要解析这些资源。类CYBundleInputSourceResolver
提供用于从bundle加载资源。前面的示例可以重写为使用该类,如下所示
// obtain XSL as data from somewhere...
NSData *xslData = nil;
// create template instance
CYTemplate *tmpl = [CYTemplate templateWithData:xslData];
// add bundle resolver (using the main bundle)
tmpl.inputSourceResolver = [CYBundleInputSourceResolver new];
实体解析
有时你可能需要处理引用无法解析的实体的XML文档,例如这个没有任何DTD的文档
<?xml version="1.0" encoding="UTF-8"?>
<content>
<para>© 2016 Bad XML Citizen</para>
</content>
CYEntityResolver
API 允许对实体如 ©
在运行时以简单的方式处理。CYSimpleEntityResolver
类提供了一种注册简单实体值的方式
[[CYSimpleEntityResolver sharedResolver] addInternalEntities:@{@"copy" : @"©"}];
默认情况下,XML 将被解析以保留实体,但你可以通过使用 libxml 标志 XML_PARSE_NOENT
来启用实体替换,如下所示
NSData *data = [@"<content><para>© 2016 Bad XML Citizen</para></content>"
dataUsingEncoding:NSUTF8StringEncoding];
id<CYInputSource> input = [[CYDataInputSource alloc] initWithData:data
options:(CYParsingOptions)(XML_PARSE_NOENT)];
此时,如果你在 input
上调用 asString:error:
,你会得到以下结果(注意 ©
的出现)
<?xml version="1.0" encoding="UTF-8"?>
<content>
<para>© 2016 Bad XML Citizen</para>
</content>
示例应用
包含在源代码库中的 CreationMatrix
项目的 示例应用程序 可以用于测试在您的数据上运行 XSLT 转换
项目集成
您可以通过 CocoaPods 或作为依赖项目手动集成 BRCybertron。
通过 CocoaPods
如果尚未安装,请安装 CocoaPods
$ [sudo] gem install cocoapods
$ pod setup
将您的 Xcode 项目的目录更改为,并创建一个类似以下的名为 Podfile
的文件
platform :ios, '7.1'
pod 'BRCybertron'
将安装到您的项目中
$ pod install
使用 CocoaPods 生成的 .xcworkspace 文件在 Xcode 中打开您的项目
注意:从版本 0.39 开始,CocoaPods 可能无法为这个包生成有效项目。您可以通过运行类似下面的 pod
命令来解决它
$ COCOAPODS_DISABLE_DETERMINISTIC_UUIDS=YES pod install