我使用 libxml2 实现架构验证。模式我正在使用以下行来验证导入其他两个模式:
<xs:import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.somewebsite.com/xsd/xml.xsd"/>
所有三个架构文件都位于设备的同一目录中。
当设备具有互联网访问权限时,这种方法很有效,但是当设备没有访问时会失败,因为即使我传入schemaLocation
,libxml2仍会尝试从XML_PARSE_NONET
下载导入的模式。
我尝试通过将schemaLocation
属性编辑为xml.xsd
,./xml.xsd
和file:///data/data/com.company.appname/files/xml.xsd
来让libxml2在本地加载文件,但这三个都导致了相同的libxml2错误:
16
3069 (XML_SCHEMAP_INTERNAL)
Internal error: xmlSchemaParse, An internal error occurred.
我还试图完全删除schemaLocation
属性,因为libxml2可能会在原始模式旁边搜索导入的模式,但是当模式解析器触及引用的行时,会导致以下错误导入的实体:
<xs:attribute ref="xml:lang" use="required"/>
16
3004 (XML_SCHEMAP_SRC_RESOLVE)
attribute use (unknown), attribute 'ref': The QName value '{http://www.w3.org/XML/1998/namespace}lang' does not resolve to a(n) attribute declaration.
我还考虑将三个模式手动合并到一个文件中,但由于它们使用不同的名称空间,因此无法实现。
标准解决方案似乎是 XML目录,但我已经通读了libxml2's catalog documentation,我无法弄清楚如何(甚至是否可以)添加部署到设备时我的应用程序使用的映射。我想我可能需要实现一个xmlExternalEntityLoader
,但是文档很简单。
如何在没有网络访问权限的情况下让libxml2导入这些模式?显然,我理想地喜欢一个与未经编辑的模式一起工作的强大解决方案,但我对包含编辑模式的快速和肮脏的内容感到满意,就像我上面描述的原始尝试一样。
上述错误来自Android设备(使用JNI),但我在iOS上遇到类似问题,解决方案也需要工作。
答案 0 :(得分:0)
执行此操作的一种方法是拦截libxml2的调用,以使用自定义xmlExternalEntityLoader
打开导入的URL。
执行此操作的基本代码如下:
#include <libxml/xmlIO.h>
#include <libxml/parserinternals.h>
xmlExternalEntityLoader defaultLoader = NULL;
xmlParserInputPtr
xmlMyExternalEntityLoader(const char *URL, const char *ID,
xmlParserCtxtPtr ctxt) {
xmlParserInputPtr ret;
const char *fileID = NULL;
/* lookup for the fileID
* The documentation suggests using the ID, but for me this was
* always NULL so I had to lookup by URL instead.
*/
ret = xmlNewInputFromFile(ctxt, fileID);
if (ret != NULL)
return(ret);
if (defaultLoader != NULL)
ret = defaultLoader(URL, ID, ctxt);
return(ret);
}
int main(..) {
...
/*
* Install our own entity loader
*/
defaultLoader = xmlGetExternalEntityLoader();
xmlSetExternalEntityLoader(xmlMyExternalEntityLoader);
...
}
(稍微调整了libxml2的I / O接口文档的The entities loader部分中的示例代码。)