3

我在 libxmljs 存储库上发布了一个问题,它已关闭,因为他们认为这在 lib 级别上不是问题。所以我把它贴在这里。

我正在尝试使用 OASIS 提供的 XML 模式验证 XLIFF 文件,但我一直收到 XSD 错误。

错误:在 Request._callback (/Users/fluxb0x/Tests/xliff_parser/main.js) 的 Document.validate (/Users/fluxb0x/Tests/xliff_parser/node_modules/libxmljs/lib/document.js:73:17) 中的 XSD 架构无效:25:21) 在 Request.self.callback (/Users/fluxb0x/Tests/xliff_parser/node_modules/request/request.js:199:22) 在 Request.emit (events.js:98:17) 在 Request. (/Users/fluxb0x/Tests/xliff_parser/node_modules/request/request.js:1160:14) 在 IncomingMessage 的 Request.emit (events.js:117:20)。(/Users/fluxb0x/Tests/xliff_parser/node_modules/request/request.js:1111:12) 在 IncomingMessage.emit (events.js:117:20) 在 _stream_readable.js:938:16 在 process._tickCallback (node. js:419:13)

我使用 Oxygen XML 编辑器来测试验证,它没有问题。

这是我导出的 XLIFF 文件:en.xliff

这是 OASIS 提供的 XSD 文件:xliff_schema.xsd

好大的文件。

感谢您的帮助。

4

3 回答 3

7

如果 XSD 架构包含xsd:import具有文件系统相关schemaLocation属性的元素,则该libxmljs.parseXml()函数接受baseUrl可用于设置这些属性的选项。

const xsdDocument = libxmljs.parseXml(xsdString, { baseUrl: "/path/to/xsd/" });

这避免了临时更改工作目录的需要。还要注意尾部的斜线。

于 2017-10-03T17:59:52.333 回答
2

正如您在libxmljs 错误跟踪器中所指出的,在libxmljs使用导入另一个模式文件的模式文件验证 XML 时会引发错误。

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

发生这种情况是因为 schemaLocation 中的相对路径是在进程当前工作目录上计算的。一种解决方法是在验证之前更改目录:

fs.readFile(schemaPath, { encoding: 'utf8' }, function (err, xsd) {
    if (err) cb (err);

    var cwd = process.cwd();
    process.chdir(path.dirname(schemaPath));

    var xsdDoc = libxml.parseXml(xsd);
    var xmlDoc = libxml.parseXml(content);

    var output = xmlDoc.validate(xsdDoc);
    process.chdir(cwd);

    cb(undefined, xmlDoc.validationErrors);
});

我不确定如何libxml处理这个问题:也许引用的文件是同步加载的,我想这是次优的。

此解决方法仅适用于本地文件,我不知道在远程 schemaLocation 的情况下如何解决,例如您的示例(schemaLocation="http://www.w3.org/2001/xml.xsd"/>

即使这不是一个真正的解决方案,我认为这可能会有所帮助。

于 2014-11-28T11:56:57.347 回答
0

如其他答案所述,libxmljs 在使用<import>来自 http 或 https url 的另一个模式文件验证 XML 时会引发错误。<import>但是,如果标签引用本地文件 url,libxmljs 就可以正常工作。

<import>此解决方案通过下载并更新内存中的 xsd 文档以引用本地副本来自动处理 xsd 中的每个元素。

它使用 axios 来获取 url,但这可以替换为您最喜欢的请求库。请注意,处理仅深入一级。如果下载的 xsds 也包含<import>元素,它们将不会被处理,尽管这种类型的递归并不难添加。

import * as libxml from "libxmljs"
import * as fs from "fs"
import * as os from "os"
import axios from "axios"

async function validateFile(file:string) {
  const fileContents = fs.readFileSync(file).toString()
  const doc = libxml.parseXml(fileContents)
  const root = doc.root()
  const schemaHref = root.namespace().href()
  const schemaLocation = root.attrs().find(a=>a.namespace().href() === 'http://www.w3.org/2001/XMLSchema-instance' && a.name() === "schemaLocation").value()
  const loc = (href:string):string=>{
    const pieces = schemaLocation.split(/\s+/)
    for (let i=0; i<pieces.length; i+=2) {
      if (pieces[i] === href) return pieces[i+1]
    }
  }
  const schemaDoc = libxml.parseXml((await axios.get(loc(schemaHref))).data)
  const importElements = schemaDoc.find("//schema:import",{schema:"http://www.w3.org/2001/XMLSchema"})
  // make any imports local
  for (const e of importElements) {
    const schemaLocation = e.attr("schemaLocation").value();
    const newFileName = os.tmpdir()+"/"+schemaLocation.replace(/[^a-z_.]/ig,'_')
    e.attr({schemaLocation:"file://"+newFileName})
    fs.writeFileSync(newFileName,(await axios.get(schemaLocation)).data)
  }
  if (!doc.validate(schemaDoc)) throw Error(doc.validationErrors.map(e=>(e.message + " at " + e.line + ":" + e.column)).join())
}
const file = "0001.xml"
validateFile(file)


于 2021-05-04T18:46:04.613 回答