我目前正在尝试使用 Spring Boot 3 / Java 17 实现符合 Open Archives Harvesting 的服务。该协议是基于 XML 的,因此我在发送时从 OAI-PMH.xsd (和其他)和 JAXB2Marshaller 生成 Java 类结果。
但是,根据 XML 验证,编组响应无效,原因是非根 XML 元素上的 xsi:schemaLocation 丢失/错位:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/"
xmlns:oai="http://www.openarchives.org/OAI/2.0/oai-identifier"
xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">
<responseDate>2024-07-03T14:02:59Z</responseDate>
<request verb="Identify">http://localhost:4040/api/export/v1/oai/Identify</request>
<Identify>
<repositoryName>repositoryName</repositoryName>
<baseURL>http://localhost:4040/api/export/v1/oai/Identify</baseURL>
<protocolVersion>2.0</protocolVersion>
<adminEmail>[email protected]</adminEmail>
<earliestDatestamp>2019-05-13T15:31:39Z</earliestDatestamp>
<deletedRecord>persistent</deletedRecord>
<granularity>YYYY-MM-DDThh:mm:ssZ</granularity>
<description>
<oai:oai-identifier xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai-identifier http://www.openarchives.org/OAI/2.0/oai-identifier.xsd">
<oai:scheme>oai</oai:scheme>
<oai:repositoryIdentifier>publications.example.com</oai:repositoryIdentifier>
<oai:delimiter>:</oai:delimiter>
<oai:sampleIdentifier>oai:publications.example.com:1234</oai:sampleIdentifier>
</oai:oai-identifier>
</description>
</Identify>
</OAI-PMH>
报错为:
cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'oai:oai-identifier'.xml(cvc-complex-type.2.4.c)
如果我(手动)将
xsi:schemaLocation
添加到 <oai:oai-identifier>
元素,则文档变得有效:
<description>
<oai:oai-identifier xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai-identifier http://www.openarchives.org/OAI/2.0/oai-identifier.xsd">
<oai:scheme>oai</oai:scheme>
<oai:repositoryIdentifier>publications.example.com</oai:repositoryIdentifier>
<oai:delimiter>:</oai:delimiter>
<oai:sampleIdentifier>oai:publications.example.com:1234</oai:sampleIdentifier>
</oai:oai-identifier>
</description>
如何在编组过程中自动将模式位置添加到元素中?
编组本身是通过 Spring 的 MarshallingHttpMessageConverter 完成的:
@Configuration
class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(
@NonNull List<HttpMessageConverter<?>> converters) {
var marshaller = new Jaxb2Marshaller();
marshaller.setContextPaths(
"org.openarchives.oai",
"org.openarchives.oai_dc",
"org.openarchives.oai_identifier",
"org.purl.dc.elements");
Map<String, ?> marshallerProperties = new HashMap<>() {
{
put(Marshaller.JAXB_FORMATTED_OUTPUT, true);
put(Marshaller.JAXB_SCHEMA_LOCATION,
"http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd");
}
};
marshaller.setMarshallerProperties(marshallerProperties);
var converter = new MarshallingHttpMessageConverter(marshaller);
converter.setDefaultCharset(StandardCharsets.UTF_8);
converters.add(0, converter);
}
}
所以,回答我自己的问题:
只需向 Marshaller 添加更多名称空间 URI/模式位置即可。在文件
WebConfig
中,所需的更改是:
marshaller.setMarshallerProperties(new HashMap<String, Object>() {
{
put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
put(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name());
put(Marshaller.JAXB_SCHEMA_LOCATION,
"http://www.openarchives.org/OAI/2.0/ https://www.openarchives.org/OAI/2.0/OAI-PMH.xsd " +
"http://www.openarchives.org/OAI/2.0/oai_dc/ https://www.openarchives.org/OAI/2.0/oai_dc.xsd");
}
});