微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

QName 的创建采用默认命名空间前缀而不是提供的参数

如何解决QName 的创建采用默认命名空间前缀而不是提供的参数

我正在使用 JaxB Marshalling 创建 XML。我的 XML 我使用 JAXB XmlAdapter 选项创建的自定义字段很少。自定义字段是使用 JAXBElement 创建的,其中 QName 是参数之一。

根据 QName 文档,它需要 3 个参数 NamespaceURILocalPartPrefix。我正在传递所有这些参数。但出于某种原因,创建的 XML 采用认命名空间前缀 ns0,ns1,ns2 等,而不是 QName 创建参数中提供的前缀。

一切都按预期工作,没有任何问题。我只想知道如何让 QName 占用我作为参数传递的 custom prefix 值,而不是它自动添加default namespace prefix 。我知道,如果我不传递 prefix 值,那么它将采用 default namespace prefix 但在我的情况下,即使在传递 custom prefix 值之后,它也会分配 default namespaces prefixXML 我想避免。我尝试了很多东西,但仍然没有奏效。

注意:我没有使用 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 中的现有功能之上提供了各种额外的好处。发布此答案,因为它可能对将来的某人有所帮助:

  1. 删除 package-info.java 及其所有内容(如果您在尝试某些内容时添加了它,因为我看到这里的很多答案都是基于它的)。

  2. 由于您使用的是 Moxy,因此您可以使用所有必需的 NamespcaeURIPrefix 创建地图。像这样:

    Map<String,String> urisToPrefixes = new HashMap<String,String>();
    urisToPrefixes.put("http://www.root.com","rootNS");
    urisToPrefixes.put("http://sub.root.com","subNS"); 
  1. 在使用编组方法时添加属性并将此 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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?