如果我有一个简单的 xsd 文件和一个简单的 xml 文件,SaxonJS 是否可以显示 xml 中的哪些元素和哪些属性未在 xsd 中定义?
我一直在寻找例子,但到目前为止还没有找到任何东西。
更新
我还将接受使用 saxon-js 遍历 xml 资源并检查 xsd 资源中的元素和属性(不必检查属性值)的 js 代码(节点)的答案。
以某种有效的方式。
为了简单地检查xs:element
模式中元素的存在,一个键就足够了,对于xs:attribute
. 但是所有这一切都依赖于简单xs:element name="foo"
和xs:attribute name="att1"
使用的声明,并且绝不会检查嵌套或结构:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="element-by-name" match="xs:element" use="QName(/*/@targetNamespace, @name)"/>
<xsl:key name="attribute-by-name" match="xs:attribute" use="QName(/*/@targetNamespace, @name)"/>
<xsl:template match="*[not(key('element-by-name', node-name(), $schema-doc))]">
<element-not-declared>
<name>{node-name()}</name>
<path>{path()}</path>
</element-not-declared>
<xsl:next-match/>
</xsl:template>
<xsl:template match="@*[not(key('attribute-by-name', node-name(), $schema-doc))]">
<attribute-not-declared>
<name>{node-name()}</name>
<path>{path()}</path>
</attribute-not-declared>
</xsl:template>
<xsl:mode on-no-match="shallow-skip"/>
<xsl:template match="/" name="xsl:initial-template">
<xsl:next-match/>
<xsl:comment xmlns:saxon="http://saxon.sf.net/">Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</xsl:comment>
</xsl:template>
<xsl:param name="schema-doc">
<xs:schema>
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:element name="foo" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</xsl:param>
</xsl:stylesheet>
样本输入
<?xml version="1.0" encoding="utf-8"?>
<root>
<items count="1">
<item>
<foo>foo 1</foo>
<bar>bar 1</bar>
</item>
</items>
</root>
在浏览器中使用 Saxon-JS 2.3 运行时会给出
<attribute-not-declared>
<name>count</name>
<path>/Q{}root[1]/Q{}items[1]/@count</path>
</attribute-not-declared>
<element-not-declared>
<name>bar</name>
<path>/Q{}root[1]/Q{}items[1]/Q{}item[1]/Q{}bar[1]</path>
</element-not-declared>
<!--Run with Saxon-JS 2.3 Browser-->
但我已经测试过它也适用于“Saxon-JS 2.3 Node.js”。
因此,这会根据模式中使用的键找到一些未找到匹配声明的元素或属性。它只是一种肤浅的方法,甚至没有考虑命名空间和 elementForm 或 attributeForm 和命名空间的复杂性。
要使用 SaxonJS 运行 XSLT 3 代码,您可以使用SaxonJS.XPath.evaluate
调用 XPath 3.1transform
函数来运行 XSLT,如下所示,或者您可以先使用xslt3
命令行工具将 XSLT 导出为 SEF/JSON,然后使用SaxonJS.transform
.
const SaxonJS = require("saxon-js");
const xml = `<?xml version="1.0" encoding="utf-8"?>
<root>
<items count="1">
<item>
<foo>foo 1</foo>
<bar>bar 1</bar>
</item>
</items>
</root>`;
const xsd = `<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="element-by-name" match="xs:element" use="QName(/*/@targetNamespace, @name)"/>
<xsl:key name="attribute-by-name" match="xs:attribute" use="QName(/*/@targetNamespace, @name)"/>
<xsl:template match="*[not(key('element-by-name', node-name(), $schema-doc))]">
<element-not-declared>
<name>{node-name()}</name>
<path>{path()}</path>
</element-not-declared>
<xsl:next-match/>
</xsl:template>
<xsl:template match="@*[not(key('attribute-by-name', node-name(), $schema-doc))]">
<attribute-not-declared>
<name>{node-name()}</name>
<path>{path()}</path>
</attribute-not-declared>
</xsl:template>
<xsl:mode on-no-match="shallow-skip"/>
<xsl:template match="/" name="xsl:initial-template">
<xsl:next-match/>
<xsl:comment xmlns:saxon="http://saxon.sf.net/">Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</xsl:comment>
</xsl:template>
<xsl:param name="schema-doc">
<xs:schema>
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:element name="foo" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</xsl:param>
</xsl:stylesheet>`;
const result = SaxonJS.XPath.evaluate(`
transform(
map {
'source-node' : parse-xml($xml),
'stylesheet-text' : $xsd,
'delivery-format' : 'serialized'
}
)?output`,
[],
{
params : { xml : xml, xsd : xsd }
}
);
console.log(result);
输出
<?xml version="1.0" encoding="UTF-8"?>
<attribute-not-declared>
<name>count</name>
<path>/Q{}root[1]/Q{}items[1]/@count</path>
</attribute-not-declared>
<element-not-declared>
<name>bar</name>
<path>/Q{}root[1]/Q{}items[1]/Q{}item[1]/Q{}bar[1]</path>
</element-not-declared>
<!--Run with Saxon-JS 2.3 Node.js-->