【问题标题】:How can I import XML schema without network access?如何在没有网络访问的情况下导入 XML 架构?
【发布时间】:2014-03-12 15:28:57
【问题描述】:

我正在使用 libxml2 实现架构验证。我正在验证的架构导入了另外两个架构,其行如下:

<xs:import namespace="http://www.w3.org/XML/1998/namespace"
           schemaLocation="http://www.somewebsite.com/xsd/xml.xsd"/>

所有三个架构文件都位于设备上的同一目录中。

这在设备可以访问互联网时运行良好,但在没有互联网访问时会失败,因为 libxml2 仍会尝试从 schemaLocation 下载导入的架构,即使我传入了 XML_PARSE_NONET

我尝试通过将schemaLocation 属性编辑为xml.xsd./xml.xsdfile:///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 上遇到类似问题,解决方案也需要工作。

【问题讨论】:

    标签: android ios xml xsd libxml2


    【解决方案1】:

    一种方法是拦截 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 部分的示例代码稍作调整。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-17
      • 2018-07-12
      相关资源
      最近更新 更多