Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

SPARQL:结果格式

purrdf-sparql-results 是 SPARQL 技术栈的结果边界:它是把 SparqlResult(SELECT 解、ASK 布尔值或 CONSTRUCT 图)转换为四种 W3C SPARQL 结果格式——JSON(SRJ)、XML、CSV 与 TSV——的规范权威实现,并在格式能够承载时附加一个增补性的、由调用方命名的溯源扩展。JSON 与 XML 文档也可以读回(from_json、from_xml)。

#![allow(unused)]
fn main() {
use purrdf::{RdfDatasetBuilder, TermValue};
use purrdf::sparql::{from_json, serialize, ResultProvenance, SparqlResult, SparqlResultsFormat};

let result = SparqlResult::Solutions {
    variables: vec!["s".to_owned()],
    rows: vec![vec![Some(TermValue::Iri("https://example.org/alice".to_owned()))]],
    aux: RdfDatasetBuilder::new().freeze().expect("empty auxiliary dataset").into(),
};
let outcome = serialize(&result, SparqlResultsFormat::Json, &ResultProvenance::default(), None)
    .expect("SELECT serializes to SRJ");

assert!(!outcome.provenance_dropped);
let decoded = from_json(&outcome.bytes).expect("emitted JSON parses back");
assert_eq!(decoded.variables, ["s"]);
assert_eq!(decoded.rows, [vec![Some(TermValue::Iri("https://example.org/alice".to_owned()))]]);
}

各格式的写出器(to_json、to_xml、to_csv、to_tsv)与读取器(from_json、from_json_boolean、from_xml、from_xml_boolean)也会直接导出。

选择格式之前值得了解的行为

  • 逐字节确定的输出——同一结果总是序列化为相同的字节,与 PurRDF 其他所有输出路径一样(编解码器与确定性)。
  • 支持矩阵是强制执行的,而不是含糊处理的——XML 拒绝 CONSTRUCT 图,CSV/TSV 则同时拒绝 ASK 布尔值与 CONSTRUCT 图,各自报告为带类型的 Error::Format,而不是输出某种形似规范却错误的东西。
  • 有损投影会被标记——CSV/TSV 没有扩展点,因此已填充的溯源会在出口关卡处被裁掉,并设置 SerializeOutcome::provenance_dropped;这种丢弃绝不是静默的。当为 JSON/XML 提供了非空的 ResultProvenance、却没有可供锚定的 ProvenanceNamespace 时,也会设置同一标志——见下文。
  • RDF 1.2 基础方向使用规范自身的键——带方向字面量的基础方向序列化为 its:dir(JSON:在 "value"/"xml:lang" 旁增加一个 "its:dir" 成员;XML:<literal its:dir="…">),这与 SPARQL 1.2 Query Results 规范自身示例所用的拼写相同,也是 RDF/XML 编解码器已经输出的拼写。为了向后兼容,XML/JSON 读取器还接受本 crate 自身写出器过去产生的两种旧拼写(裸的 dir 属性,以及——仅限 XML——一个带 purrdf:dir 命名空间的属性),但当同一字面量上存在多于一种拼写时,以 its:dir 为准,并且写出的永远只有 its:dir。
格式SELECTASKCONSTRUCT溯源扩展
JSON (SRJ)是是是是,需提供命名空间
XML是是拒绝是,需提供命名空间
CSV是拒绝拒绝丢弃,并加标记
TSV是拒绝拒绝丢弃,并加标记

溯源扩展

溯源扩展是增补性的且由调用方命名:标准的 SPARQL 结果使用方可以原样读取 JSON/XML 文档,而能够识别溯源的使用方可以恢复随绑定一同携带的逐结果数据,这些数据锚定在由_调用方_提供的标识符之下——绝不是 PurRDF 生成的标识符(PurRDF 不生成任何自有的词汇表 IRI;参见 AGENTS.md 中的「不是本体」契约)。提供一个 ProvenanceNamespace——一个 prefix(即裸的顶层 JSON 成员键,也是 XML 命名空间前缀)加上 XML 命名空间 iri——作为 serialize 的第四个参数(to_json/to_xml 则作为第三个参数接受它:这两者没有需要选择的 format 参数)。ProvenanceNamespace::new 把 prefix 作为 XML Namespaces 的 NCName 进行验证(除其他情况外,拒绝 :、空白以及保留的 xml/ xmlns 名称),并把 iri 作为绝对 IRI 进行验证,因为 prefix 会被直接拼接进 XML 元素/属性名,无法像文本内容那样进行转义:

#![allow(unused)]
fn main() {
use purrdf::sparql::{from_json_boolean, ProvenanceNamespace, ResultProvenance, SparqlResult, SparqlResultsFormat, serialize};

let result = SparqlResult::Boolean(true);
let namespace = ProvenanceNamespace::new("prov", "https://example.org/provenance#")
    .expect("valid NCName prefix + absolute IRI");
let provenance = ResultProvenance {
    query_hash: Some("example-query".to_owned()),
    ..ResultProvenance::default()
};
let outcome = serialize(&result, SparqlResultsFormat::Json, &provenance, Some(&namespace))
    .expect("ASK with caller-named provenance serializes");
assert!(!outcome.provenance_dropped);
assert!(from_json_boolean(&outcome.bytes).expect("emitted ASK parses back"));
let without_namespace = serialize(&result, SparqlResultsFormat::Json, &provenance, None)
    .expect("ASK without a provenance namespace serializes");
assert!(without_namespace.provenance_dropped);
}

当 namespace: None 时,无论 ResultProvenance 填充了多少内容,JSON/XML 都完全不输出溯源元素/成员——这与 CSV/TSV 一贯采用的「丢弃并标记」契约相同。在格式完全没有扩展点的地方(CSV/TSV),无论 namespace 如何,溯源都会被丢弃并显式告知,遵循切片、映射与溯源中描述的损失纪律。

唯一的项语法权威

该 crate 依赖 purrdf-core、purrdf-lex 和 purrdf-iri,并保持 wasm 洁净。共享的词法读取器和 IRI 验证服务于结果格式;项与 N-Triples 语法来自内核的输出原语以及共享的词法项写出器。因此,结果、编解码器和诊断使用同一个项语法权威实现。

相关内容