如何解决QName 的创建采用默认命名空间前缀而不是提供的参数
我正在使用 JaxB Marshalling
创建 XML
。我的 XML 我使用 JAXB XmlAdapter
选项创建的自定义字段很少。自定义字段是使用 JAXBElement
创建的,其中 QName
是参数之一。
根据 QName
文档,它需要 3 个参数 NamespaceURI
、LocalPart
和 Prefix
。我正在传递所有这些参数。但出于某种原因,创建的 XML
采用默认命名空间前缀 ns0,ns1,ns2
等,而不是 QName
创建参数中提供的前缀。
一切都按预期工作,没有任何问题。我只想知道如何让 QName
占用我作为参数传递的 custom prefix
值,而不是它自动添加的 default namespace prefix
。我知道,如果我不传递 prefix
值,那么它将采用 default namespace prefix
但在我的情况下,即使在传递 custom prefix
值之后,它也会分配 default namespaces prefix
到 XML
我想避免。我尝试了很多东西,但仍然没有奏效。
注意:我没有使用 javax Jaxb
库,而是使用基于 EclipseLink Moxy
实现的 Jaxb
。
目前,创建的 XML 看起来像这样:(请注意,这些不是根元素或 XML 标头,而是取自 XML 的某个部分)。
<ns0:MainField xmlns:ns0="https://google.com?xsd=google.xsd">
<ns1:SubField1 xmlns:ns1="https://fb.com?xsd=fb.xsd">
<ns2:Field1 xmlns:ns2="https://fb.com?xsd=fb.xsd">Value1</ns2:Field1>
</ns1:SubField1>
<ns3:SubField3 xmlns:ns3="https://google.com?xsd=google.xsd">SubValue3</ns3:SubField3>
</ns0:MainField>
<ns4:MainField2 xmlns:ns4="https://google.com?xsd=google.xsd">MainValue2</ns4:MainField2>
根据我提供给 QName
字段的值,我期望它看起来像这样:
<google:MainField xmlns:google="https://google.com?xsd=google.xsd">
<fb:SubField1 xmlns:fb="https://fb.com?xsd=fb.xsd">
<fb:Field1 xmlns:fb="https://fb.com?xsd=fb.xsd">Value1</fb:Field1>
</fb:SubField1>
<google:SubField3 xmlns:google="https://google.com?xsd=google.xsd">SubValue3</google:SubField3>
</google:MainField>
<google:MainField2 xmlns:google="https://google.com?xsd=google.xsd">MainValue2</google:MainField2>
以下是我的 Java
类,它正在创建 QName
。我有一个基于创建 Map<String,Object>
的值类型的 QName
。除了 QName namespace prefix
部分外,一切都按预期工作。
import io.openepcis.service.jaxb.DefaultJsonSchemaNamespaceURIResolver;
import jakarta.xml.bind.JAXBElement;
import jakarta.xml.bind.annotation.XmlAnyElement;
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.xml.namespace.QName;
import org.apache.commons.lang3.NotImplementedException;
public class MapAdapter extends XmlAdapter<MapWrapper,Map<String,Object>> {
DefaultJsonSchemaNamespaceURIResolver uriResolver = new DefaultJsonSchemaNamespaceURIResolver();
@Override
public Map<String,Object> unmarshal(MapWrapper valueType) throws Exception {
throw new NotImplementedException();
}
@Override
public MapWrapper marshal(Map<String,Object> extensions) throws Exception {
if (extensions == null) {
return null;
}
MapWrapper wrapper = new MapWrapper();
List elements = new ArrayList();
//Loop through the Extensions MAP
for (Map.Entry<String,Object> property : extensions.entrySet()) {
final Optional<String> xmlNamespace = uriResolver.namespaceURIFromSchema(extension.getKey());
String namespaceURI = xmlNamespace.get();
String localPart = getLocalPart(property.getKey());
String prefix = getPrefix(property.getKey());
String label = getCleanLabel(property.getKey());
System.out.println(" namespaceURI : " + namespaceURI + " localPart : " + localPart + " prefix : " + prefix);
//If the Value type is MAP then recurse through the loop
if (property.getValue() instanceof Map) {
elements.add(new JAXBElement<MapWrapper>(new QName(namespaceURI,localPart,prefix),MapWrapper.class,marshal((Map) property.getValue())));
} else if (property.getValue() instanceof String) {
// If the Value type is String then directly create JAXBElement
elements.add(new JAXBElement<String>(new QName(namespaceURI,String.class,property.getValue().toString()));
}
}
wrapper.elements = elements;
return wrapper;
}
// Formats the complete Label for the XML tag
public static String getCleanLabel(String label) {
label = label.replaceAll("[()]","").replaceAll("[^\\w\\s]","_").replaceAll(" ","_");
return label;
}
//Formats the LocalPart of the XML Tag (after ":")
public static String getLocalPart(String localPart) {
localPart = localPart.substring(localPart.indexOf(":") + 1);
return localPart;
}
//Formats the Prefix of the XML Tag (before ":")
public static String getPrefix(String prefix) {
prefix = prefix.substring(0,prefix.indexOf(":"));
return prefix;
}
}
class MapWrapper {
@XmlAnyElement
List elements;
}
class DefaultJsonSchemaNamespaceURIResolver{
private static Map<String,String> xmlNamespaces = new HashMap<String,String>();
static {
xmlNamespaces.put("google","https://google.com");
xmlNamespaces.put("fb","https://fb.com");
xmlNamespaces.put("insta","https://instagram.com");
}
public Optional<String> namespaceURIFromSchema(String schemaURI) {
if (xmlNamespaces.containsKey(schemaURI)) {
return Optional.of(xmlNamespaces.get(schemaURI));
}
return Optional.empty();
}
}
以下是我在 Maven pom.xml
中使用的依赖项:
<!-- JAXB Annotations Dependencies START -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>3.0.0</version>
</dependency>
<!-- JAXB Annotations Dependencies END -->
解决方法
在尝试了很多东西并参考了很多东西之后,我终于明白了。我正在使用 Moxy
依赖项而不是 Jaxb
,因为它在 Jaxb
中的现有功能之上提供了各种额外的好处。发布此答案,因为它可能对将来的某人有所帮助:
-
删除
package-info.java
及其所有内容(如果您在尝试某些内容时添加了它,因为我看到这里的很多答案都是基于它的)。 -
由于您使用的是
Moxy
,因此您可以使用所有必需的NamespcaeURI
和Prefix
创建地图。像这样:
Map<String,String> urisToPrefixes = new HashMap<String,String>();
urisToPrefixes.put("http://www.root.com","rootNS");
urisToPrefixes.put("http://sub.root.com","subNS");
- 在使用编组方法时添加属性并将此 Map 作为参数发送:
marshaller.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER,urisToPrefixes);
这将确保每当遇到 Namespace
时,它都会检查相应的 prefix
并将其添加到 XML 标头中,这样它将替换所有默认前缀 ns0、ns1 等到地图中相应的前缀。
JAXBContext ctx = JAXBContext.newInstance(new Class[] { TestObject.class,SubObject.class });
Map<String,String>();
urisToPrefixes.put("http://www.root.com","rootNS");
urisToPrefixes.put("http://sub.root.com","subNS");
Marshaller m = ctx.createMarshaller();
m.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER,prefixesToUris);
如果您想了解更多信息,请关注official documentation here。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。