Saxon执行XQuery时如何使用XSD中定义的类型解决计算精度问题
问题描述
我有如下XML文档:
<?xml version="1.0" encoding="UTF-8"?> <root xsi:noNamespaceSchemaLocation="example.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <a>0.1</a> <b>0.2</b> </root>
该文档关联了以下XSD:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element name="a" type="xs:decimal"/> <xs:element name="b" type="xs:decimal"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
我使用如下代码片段执行XQuery表达式 let $a := /root/a, $b := /root/b, $res := $a + $b return $res:
var proc = new Processor(false); var builder = proc.newDocumentBuilder(); builder.setBaseURI(URI.create("http://test.ru")); var file = new File(filePath); var doc = builder.build(file); var expression = "let $a := /root/a, $b := /root/b, $res := $a + $b return $res"; var compiler = proc.newXQueryCompiler(); var executable = compiler.compile(expression); var selector = executable.load(); selector.setContextItem(doc); return selector.evaluate();
运行结果为 0.30000000000000004,该误差是默认采用number/xs:double类型导致的。
但我的XSD中已定义元素a和b为xs:decimal类型,有没有办法让Saxon在执行XQuery表达式时调用XSD中定义的类型?
更新
我已获取SaxonEE试用许可,通过如下代码加载许可:
var conf = new com.saxonica.config.EnterpriseConfiguration(); conf.setConfigurationProperty(Feature.LICENSE_FILE_LOCATION, "/path/to/saxon-license.lic"); var proc = new Processor(conf);
我仍使用相同的XML文档和XSD,同时在XQuery表达式的序言部分添加了import schema语句:
import schema default element namespace "" at "/path/to/example.xsd"; let $a := /root/a, $b := /root/b, $res := $a + $b return $res
但运行结果仍然是0.30000000000000004,请问我的操作哪里存在问题?
更新2
结合所有建议,以下是使用Saxon-EE实现模式感知XQuery查询的可运行示例:
var conf = new com.saxonica.config.EnterpriseConfiguration(); conf.setConfigurationProperty(Feature.LICENSE_FILE_LOCATION, "/path/to/saxon-license.lic"); conf.setSchemaValidationMode(net.sf.saxon.lib.Validation.STRICT); var proc = new Processor(conf); var schemaManager = proc.getSchemaManager(); var source = new SAXSource(new InputSource("/path/to/example.xsd")); schemaManager.load(source); var builder = proc.newDocumentBuilder(); builder.setBaseURI(URI.create("http://test.ru")); var file = new File(filePath); var doc = builder.build(file); var prolog = "import schema default element namespace \"\" at \"/path/to/example.xsd\";" var expression = prolog + "let $a := /root/a, $b := /root/b, $res := $a + $b return $res"; var compiler = proc.newXQueryCompiler(); var executable = compiler.compile(expression); var selector = executable.load(); selector.setContextItem(doc); return selector.evaluate();
问题原因与解决方案
之前运行结果不符合预期,是因为缺失两个必要配置:
- 默认情况下Saxon解析XML文档仅读取节点文本内容,不会自动触发XSD校验,也不会给节点附加XSD中定义的类型信息,运算时会默认将文本转为xs:double类型计算,自然会出现浮点数精度误差。
- 仅在XQuery头部添加
import schema仅能让查询编译器识别类型定义,需要提前将XSD加载到Saxon的SchemaManager中,同时开启XML文档的严格校验模式,才能在解析XML时给对应节点打上xs:decimal的类型标记。
你最后给出的更新2的代码已经补全了所有必要配置,运行后会按照xs:decimal规则执行加法运算,得到正确结果0.3。
内容的提问来源于stack exchange,提问作者Dmitriy
相关产品推荐
相关产品推荐

