BRCybertron 1.1.1

BRCybertron 1.1.1

测试已测试
Lang语言 CC
许可 MIT
发布最后发布2019年5月

Matt Magoffinwmjesstaylor 维护。



  • 作者
  • Matt Magoffin

BRCybertron - セイバートロン

BRCybertron 是一个用于执行 XSLT 1.0 转换的 Objective-C 框架。它作为一个轻量级的包装器实现,围绕 libxsltlibxml

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:importxsl: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>&copy; 2016 Bad XML Citizen</para>
</content>

CYEntityResolver API 允许对实体如 &copy; 在运行时以简单的方式处理。CYSimpleEntityResolver 类提供了一种注册简单实体值的方式

[[CYSimpleEntityResolver sharedResolver] addInternalEntities:@{@"copy" : @"&#169;"}];

默认情况下,XML 将被解析以保留实体,但你可以通过使用 libxml 标志 XML_PARSE_NOENT 来启用实体替换,如下所示

NSData *data = [@"<content><para>&copy; 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