当前位置: 首页 > 知识库问答 >
问题:

QName 的创建采用默认的 namesapce 前缀,而不是提供的参数

晏华奥
2023-03-14

我使用JaxB编组来创建XML。我的XML我有几个自定义字段,我使用<code>JAXB XmlAdapter<code>选项创建这些字段。自定义字段是使用<code>JAXBElement

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

一切都按预期工作,没有任何问题。我只是想知道如何让QName占用我作为参数传递的自定义前缀值,而不是它自动添加的默认命名空间前缀。我知道,如果我不传递prefix值,那么它将采用默认命名空间前缀,但在我的情况下,即使在传递自定义前缀值之后,它也将默认命名空间前缀分配给我想要避免的XML。我尝试了很多方法,但仍然没有效果。

注意:我没有使用javax Jaxb库,而是使用基于Jaxb实现的Eclipse Link 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">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

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();
    }
}


以下是我在Mavenpom.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 -->

共有1个答案

梁丘宏硕
2023-03-14
匿名用户

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

> < li>

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

由于您使用的是< code>Moxy,因此您可以使用所有必需的< code>NamespcaeURI和< code >前缀来创建地图。大概是这样的:

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

这将确保每当遇到< code >名称空间时,它将检查相应的< code >前缀,并将其添加到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");        
 
Marshaller m = ctx.createMarshaller();
m.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, prefixesToUris);

如果你想了解更多,请点击这里阅读官方文档。

 类似资料:
  • 我有一个运行在上。 我使用来提供静态文件,即生成的包,但这是不相关的。 我想要实现的是: 关于我想提供。我能做到。 在我想为。 在我想提供。 最后两个,我做不到。当我进入或我收到了默认的nginx页面。 为了使事情更加混乱被完全注释掉。 此外,如果在的块中,我将替换为,我将获得该特定项目的服务,但是我将无法为另一个服务。 下面,我将向您展示我的nginx配置 谢谢你的帮助! 编辑 我找到的解决方案

  • 问题内容: 我正在编写的代码()包括让每个客户在处理的特定时间点插入自己的计算器的功能。这是为了允许自定义业务规则。至此,计算已经完成,我们知道了很多事情,其中​​有些可能与计算有关。 将为一组特定的输入参数创建并运行一次。 我的计划是使用依赖注入在构造函数中给出一个。这允许不同的用户插入自己的。该会返回一个表示为这个特殊的运行支付的附加费的数额。其他人将实现各种计算器,我需要能够更新我的代码而不

  • 问题内容: 在Swift中处理可选选项的习惯用法似乎过于冗长,如果您只想在nil为零的情况下提供默认值,则它是: 涉及不必要地复制代码,或 这不需要是常数。 Scala的Option monad(与Swift的Optional基本相同)具有用于此目的的方法: 我想念什么吗?Swift已经有一种紧凑的方式做到这一点吗?否则,是否可以在扩展名中为Optional 定义? 问题答案: 更新资料 苹果现在

  • 标准中似乎没有规则提到模板参数需要默认参数的情况。 在dcl中。fct。默认值#1 如果在参数声明中指定了初始化子句,则将此初始化子句用作默认参数。缺省参数将用于缺少尾随参数的调用。 在本节中,规则明确描述了何时为函数调用提供默认参数。但是,我在标准中没有找到与上面描述何时提供默认参数作为模板参数的语句类似的引用。 例如

  • 在Swift中处理选项的习惯用法似乎过于冗长,如果您只想在值为零的情况下提供一个默认值: 涉及不必要的代码复制,或者 这需要不是常量。 Scala的选项monad(与Swift的可选选项基本相同)的方法是: 我错过什么了吗?斯威夫特已经有了一个紧凑的方法来实现这一点吗?或者,如果做不到这一点,是否可以在可选的扩展中定义?