我在libxmljs存储库上发布了一个问题,因为他们认为这不是lib级别的问题所以它已经关闭了。所以我在这里发布。
我尝试使用OASIS提供的XML架构验证XLIFF文件,但我一直收到XSD错误。
错误:XSD架构无效 在Document.validate(/Users/fluxb0x/Tests/xliff_parser/node_modules/libxmljs/lib/document.js:73:17) 在Request._callback(/Users/fluxb0x/Tests/xliff_parser/main.js:25:21) 在Request.self.callback(/Users/fluxb0x/Tests/xliff_parser/node_modules/request/request.js:199:22) 在Request.emit(events.js:98:17) 在请求。 (/Users/fluxb0x/Tests/xliff_parser/node_modules/request/request.js:1160:14) 在Request.emit(events.js:117:20) 在IncomingMessage。 (/Users/fluxb0x/Tests/xliff_parser/node_modules/request/request.js:1111:12) 在IncomingMessage.emit(events.js:117:20) at _stream_readable.js:938:16 at process._tickCallback(node.js:419:13)
我已经使用Oxygen XML编辑器来测试验证,它没有问题。
这是我导出的XLIFF文件:en.xliff
这是OASIS提供的XSD文件:xliff_schema.xsd
非常大的文件。
感谢您的帮助。
答案 0 :(得分:1)
如果XSD架构包含具有文件系统相对/i
属性的xsd:import
元素,则schemaLocation
函数接受libxmljs.parseXml()
选项,可用于设置这些元素的位置
baseUrl
这避免了临时更改工作目录的需要。注意尾随斜线。
答案 1 :(得分:0)
正如您在libxmljs bug tracker上所述,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"/>
)
即使它不是真正的解决方案,我认为这可能有所帮助。
答案 2 :(得分:0)
如其他答案中所述,libxmljs 在使用架构文件验证 XML 时会引发错误,该架构文件 <import>
来自 http 或 https url。但是,如果 <import>
标记引用本地文件 url,libxmljs 可以正常工作。
此解决方案通过下载 xsd 并更新内存中的 xsd 文档以引用本地副本来自动处理 xsd 中的每个 <import>
元素。
它使用 axios 来获取 url,但这可以替换为您最喜欢的请求库。请注意,处理仅深入一层。如果下载的 xsd 也包含 <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)