QName的创建使用默认的nameapce前缀而不是提供的参数 [英] Creation of QName takes default namesapce prefix rather than the provided parameter

查看:50
本文介绍了QName的创建使用默认的nameapce前缀而不是提供的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 JaxB编组创建 XML .我的XML我有几个使用 JAXB XmlAdapter 选项创建的自定义字段.使用 JAXBElement 创建自定义字段,其中 QName 是参数之一.

根据 QName 文档,它包含3个参数: NamespaceURI LocalPart Prefix .我通过所有这些参数.但是由于某种原因,创建的 XML 采用默认的名称空间前缀 ns0,ns1,ns2 等,而不是 QName 创建参数中提供的名称空间前缀.

一切正常,没有任何问题.我只想知道如何使 QName 占用我作为参数传递的自定义前缀值,而不是默认名称空间前缀>它会自动添加.我知道,如果我不传递 prefix 值,那么它将采用默认名称空间前缀,但就我而言,即使传递了 custom前缀值,它将默认名称空间前缀分配给 XML ,这是我要避免的.我尝试了很多事情,但还是没有解决.

注意:我没有使用 javax Jaxb libraray,而是使用了基于 Jaxb 实现的 EclipseLink Moxy .

当前,创建的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">值1</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 .根据创建 QName 的值的类型,我有一个 Map< String,Object> .除了 QName名称空间前缀部分.

  import io.openepcis.service.jaxb.DefaultJsonSchemaNamespaceURIResolver;导入jakarta.xml.bind.JAXBElement;导入jakarta.xml.bind.annotation.XmlAnyElement;导入jakarta.xml.bind.annotation.adapters.XmlAdapter;导入java.util.ArrayList;导入java.util.List;导入java.util.Map;导入java.util.Optional;导入javax.xml.namespace.QName;导入org.apache.commons.lang3.NotImplementedException;公共类MapAdapter扩展了XmlAdapter< MapWrapper,Map< String,Object>>.{DefaultJsonSchemaNamespaceURIResolver uriResolver =新的DefaultJsonSchemaNamespaceURIResolver();@Override公共Map< String,Object>unmarshal(MapWrapper valueType)引发异常{抛出新的NotImplementedException();}@Override公共MapWrapper编组(Map< String,Object>扩展)引发异常{if(扩展名== null){返回null;}MapWrapper包装器=新的MapWrapper();列表元素= new ArrayList();//通过扩展MAP循环对于(Map.Entry< String,Object>属性:extensions.entrySet()){final可选< String>xmlNamespace = uriResolver.namespaceURIFromSchema(extension.getKey());字符串命名空间URI = xmlNamespace.get();字符串localPart = getLocalPart(property.getKey());字符串前缀= getPrefix(property.getKey());字符串标签= getCleanLabel(property.getKey());System.out.println("namespaceURI:" + namespaceURI +"localPart:" + localPart +前缀:" +前缀);//如果Value类型为MAP,则循环遍历如果(Map的property.getValue()实例){elements.add(new JAXBElement< MapWrapper>(new QName(namespaceURI,localPart,prefix),MapWrapper.class,marshal((Map)property.getValue()))));} else if(property.getValue()instanceof String){//如果Value类型为String,则直接创建JAXBElementelements.add(new JAXBElement< String>(new QName(namespaceURI,localPart,prefix),String.class,property.getValue().toString()));}}wrapper.elements =元素;返回包装;}//格式化XML标签的完整标签公共静态字符串getCleanLabel(字符串标签){label = label.replaceAll("[()]",").replaceAll("[^ \\ w \ s]","_").replaceAll(","_");返回标签;}//格式化XML标签的LocalPart(在:"之后)公共静态字符串getLocalPart(String localPart){localPart = localPart.substring(localPart.indexOf(":)+ 1);返回localPart;}//格式化XML标签的前缀(在:"之前)公共静态字符串getPrefix(字符串前缀){prefix = prefix.substring(0,prefix.indexOf(":)));返回前缀;}}MapWrapper类{@XmlAnyElement列出元素;}类DefaultJsonSchemaNamespaceURIResolver {私有静态Map< String,String>xmlNamespaces = new HashMap< String,String>();静止的 {xmlNamespaces.put("google","https://google.com");xmlNamespaces.put("fb","https://fb.com");xmlNamespaces.put("insta","https://instagram.com");}public可选< String>namespaceURIFromSchema(String schemaURI){如果(xmlNamespaces.containsKey(schemaURI)){返回Optional.of(xmlNamespaces.get(schemaURI));}返回Optional.empty();}} 

以下是我在 Maven pom.xml 中使用的依赖项:

 <!-JAXB批注依赖项START-><依赖关系>< groupId> jakarta.xml.bind</groupId>< artifactId> jakarta.xml.bind-api</artifactId>< version> 3.0.1</version></dependency><依赖关系>< groupId> org.eclipse.persistence</groupId>< artifactId> eclipselink</artifactId>< version> 3.0.0</version></dependency><!-JAXB注释依赖项END-> 

解决方案

尝试了很多东西并参考了很多东西之后,我才能够得到它.我使用的是 Moxy 依赖项,而不是 Jaxb ,因为它在 Jaxb 中的现有功能之外还提供了各种其他好处.发布此答案,因为它可能对将来的某人有所帮助:

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

  2. >
  3. 由于使用的是 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"); 

  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 = new HashMap< String,String>();urisToPrefixes.put("http://www.root.com","rootNS");urisToPrefixes.put("http://sub.root.com","subNS");马歇尔m = ctx.createMarshaller();m.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER,prefixesToUris); 

如果您想了解更多信息,请遵循官方文档在这里.

I am using the JaxB Marshalling to create the XML. My XML I have few custom fields which I am creating using the JAXB XmlAdapter option. The custom fields are created using the JAXBElement, in which QName is one of the parameters.

As per the QName documentation it takes 3 parameters NamespaceURI, LocalPart and Prefix. I am passing all these parameters. But for some reason, the created XML takes the default namespace prefix ns0, ns1, ns2 etc rather than the provided one in the QName creation parameter.

Everything is working as expected without any issue. I just want to know how can I make the QName take up the custom prefix value that I am passing as a parameter rather than the default namespace prefix it's adding automatically. I am aware that if I do not pass the prefix value then it would take the default namespace prefix but in my case, even after passing the custom prefix value, it's assigning the default namespaces prefix to XML which I want to avoid. I tried many things but still, nothing worked out.

Note: I am not using the javax Jaxb libraray rather than that I am using the EclipseLink Moxy which is based on Jaxb implementation.

Currently, the created XML would look something like this: (Please note that these do not root elements or XML header rather these are chunks taken from a certain part of the 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>

Where as I am expecting it to look something like this based on the values I have provided to the QName field:

   <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>

Following is my Java class which is creating the QName. I have a Map<String, Object> based on the type of value it's creating the QName. Everything is working as expected except the part of the 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, localPart, prefix), 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();
    }
}


Following are the dependencies I am using in my 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 -->

解决方案

After trying a lot of things and referring to many things I was able to get it. I am using the Moxy dependency instead of Jaxb as it provides various additional benefits on top of the existing features in Jaxb. Posting this answer as it can be helpful to someone in the future:

  1. Remove the package-info.java and all of its content (if you have added it while trying something because I see a lot of answers here are based on it).

  2. Since you are using the Moxy you can create a Map with all of the required NamespcaeURI and Prefix. Something like this:

    Map<String, String> urisToPrefixes = new HashMap<String, String>();
    urisToPrefixes.put("http://www.root.com", "rootNS");
    urisToPrefixes.put("http://sub.root.com", "subNS"); 

  1. While using the Marshalling approach add the property and send this Map as a parameter:

marshaller.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, urisToPrefixes);

This will ensure that whenever a Namespace is encountered it would check for the respective prefix and add it to the XML header so in this way it would replace all the default prefix ns0,ns1, etc to the corresponding prefix from the map.

JAXBContext ctx = JAXBContext.newInstance(new Class[] { TestObject.class, SubObject.class });
 
Map<String, String> urisToPrefixes = new HashMap<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);

If you would like to read more about it then follow the official documentation here.

这篇关于QName的创建使用默认的nameapce前缀而不是提供的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆