是否可以自定义 JAXB 在编组到字符串时使用的名称空间前缀?

发布于 2024-08-16 19:43:20 字数 1608 浏览 2 评论 0原文

例如,我有一个导入另一个架构的简单架构。第二个架构(urn:just:attributes, just-attributes.xsd)仅定义属性组。

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.example.org/MySchema"
    xmlns:tns="http://www.example.org/MySchema" 
    elementFormDefault="qualified"
    xmlns:ja="urn:just:attributes">

    <import schemaLocation="just-attributes.xsd" namespace="urn:just:attributes"/>

    <element name="MyElement">
        <complexType>
            <attributeGroup ref="ja:AttributeGroup"/>
        </complexType>
    </element>
</schema>

我正在使用 Metro xjc Ant 任务根据该架构生成类。我遇到的问题是,我正在交互的第三方应用程序对于命名空间来说是特殊的。这种情况下我需要一个字符串值,所以我必须序列化它。我为此使用样板代码。

private static <T> String marshal(T object) throws JAXBException{
    OutputStream outputStream = new ByteArrayOutputStream();
    JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.marshal(object, outputStream);
    return outputStream.toString();
}

这给了我一些类似的东西

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:MyElement xmlns:ns1="urn:just:attributes" xmlns:ns2="http://www.example.org/MySchema" ns1:attrib1="1234" ns1:attrib2="5678"/>

我遇到的问题是这个第三方期望像 xmlns:thirdpartyns="urn:just:attributes" 这样的东西,也就是说,他们正在根据赋予命名空间的名称必须是“第三方”,他们的软件才能运行。

有谁知道解决这个问题的方法,除了在结果字符串中进行查找和替换之外?也许是自定义绑定规则?

For example, I've got a simple schema which imports another schema. The second schema (urn:just:attributes, just-attributes.xsd) just defines an attribute group.

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.example.org/MySchema"
    xmlns:tns="http://www.example.org/MySchema" 
    elementFormDefault="qualified"
    xmlns:ja="urn:just:attributes">

    <import schemaLocation="just-attributes.xsd" namespace="urn:just:attributes"/>

    <element name="MyElement">
        <complexType>
            <attributeGroup ref="ja:AttributeGroup"/>
        </complexType>
    </element>
</schema>

I'm using the Metro xjc Ant task to generate classes off of this schema. The problem I'm running into is that the third party application I'm interacting with is peculiar about namespaces. This case I need a String value, so I have to serialize it. I use boilerplate code for this.

private static <T> String marshal(T object) throws JAXBException{
    OutputStream outputStream = new ByteArrayOutputStream();
    JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.marshal(object, outputStream);
    return outputStream.toString();
}

Which gives me something along the lines of

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:MyElement xmlns:ns1="urn:just:attributes" xmlns:ns2="http://www.example.org/MySchema" ns1:attrib1="1234" ns1:attrib2="5678"/>

The problem I have is that this third party expects something like xmlns:thirdpartyns="urn:just:attributes", which is to say, they are parsing based on the name given to the namespace. It has to be "thirdpartyns" for their software to work.

Does anyone know of a way around this, short of doing a find and replace in the resulting string? A custom binding rule perhaps?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

久而酒知 2024-08-23 19:43:20

http://hwellmann.blogspot.com/2011/03 /jaxb-marshalling-with-custom-namespace.html

这展示了如何做到这一点。

其他:
http://www.systemmobile.com/?p=280

链接时的关键位也消失了:

在 com.sun.xml.bind.marshaller 包中找到的 NamespacePrefixMapper 类。抽象类有一个要实现的方法:

public abstract String getPreferredPrefix(  
     String namespaceUri,         
     String suggestion,         
     boolean requirePrefix); 

那么

Marshaller marshaller =        
    jaxbContext.createMarshaller();        
marshaller.setProperty(”com.sun.xml.bind.namespacePrefixMapper”,        
    new MyNamespacePrefixMapper());  

如果您还使用 javax.xml.xpath.XPath,您的 NamespacePrefixMapper 也可以实现 javax.xml.namespace.NamespaceContext,将命名空间自定义集中在单个类中。

http://hwellmann.blogspot.com/2011/03/jaxb-marshalling-with-custom-namespace.html

This shows how to do it.

Another:
http://www.systemmobile.com/?p=280

Key bits in case that link dies too:

the NamespacePrefixMapper class, found in the com.sun.xml.bind.marshaller package. The abstract class has one method to implement:

public abstract String getPreferredPrefix(  
     String namespaceUri,         
     String suggestion,         
     boolean requirePrefix); 

then

Marshaller marshaller =        
    jaxbContext.createMarshaller();        
marshaller.setProperty(”com.sun.xml.bind.namespacePrefixMapper”,        
    new MyNamespacePrefixMapper());  

If you’re also using javax.xml.xpath.XPath, your NamespacePrefixMapper can also implement javax.xml.namespace.NamespaceContext, centralizing your namespace customization in a single class.

天暗了我发光 2024-08-23 19:43:20

我在 Java SE6 中测试了,与 Java SE 的解决方案相比,它需要进行一些小的更改5(如上面所述):

    Marshaller m = context.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
    m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
    m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", mapper);

因此上面的第三个属性包含附加的.internal。包名称中与 Java SE5 版本的比较。
我还没有找到的是如何告诉 Marshaller 哪个命名空间 URI 成为默认命名空间 ("")。如果我重写方法 getPreferredPrefix() 并返回空字符串,则编组器在写入默认命名空间的属性时会出现问题(在本例中,它会创建一个名为 ns1 的新命名空间)

I tested that in Java SE6 and it requires a small change compared to the solution for Java SE 5 (as described above):

    Marshaller m = context.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
    m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
    m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", mapper);

So the third property from above contains the additional .internal. in the package name compared to the Java SE5 version.
What I did not find out yet is how to tell the Marshaller which namespace URI becomes the default namespace (""). If I override the method getPreferredPrefix() and return an empty string, the Marshaller has issues with writing attributes of the default namespace (in this case it creates a new namespace called ns1)

野生奥特曼 2024-08-23 19:43:20

我也有同样的问题。在 package-info.java 中(如果没有,您可以手动创建它)添加 xmlns 部分:

@javax.xml.bind.annotation.XmlSchema(xmlns = {
        @javax.xml.bind.annotation.XmlNs(namespaceURI = "urn:just:attributes", prefix = "thirdpartyns") }, 
        elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)

I had the same question. In package-info.java (if you don't have it, you can just manually create it) add the xmlns part:

@javax.xml.bind.annotation.XmlSchema(xmlns = {
        @javax.xml.bind.annotation.XmlNs(namespaceURI = "urn:just:attributes", prefix = "thirdpartyns") }, 
        elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
何时共饮酒 2024-08-23 19:43:20

有一种方法可以做到这一点,它使用名为 NamespacePrefixMapper 的内部 JAXB 实现类。在 JAXB RI 中,它位于 com.sun.xml.bind.marshaller 中,但在 Java6 中,它位于 com.sun.xml.internal.bind.marshaller 中。

这是一个抽象类,您可以对其进行子类化并实现将命名空间 URI 映射到前缀的抽象方法。

然后,您将该子类的一个实例注入到编组器中:

JAXBContext context = ...
Marshaller marshaller = context.createMarshaller();
NamespacePrefixMapper prefixMapper = new MyPrefixMapperImpl();
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", prefixMapper);

Java6 版本的属性名称将有所不同,但您明白了。

请注意,这是一个内部 JAXB 实现类,因此不能保证它会出现在未来的版本中。

There is a way of doing this, which uses an internal JAXB implementation class called NamespacePrefixMapper. In the JAXB RI, this is in com.sun.xml.bind.marshaller, but in Java6, it's in com.sun.xml.internal.bind.marshaller.

This is an abstract class, which you can subclass and implement the abstract method which maps namespace URIs on to prefixes.

You then inject an instance of that subclass into the marshaller:

JAXBContext context = ...
Marshaller marshaller = context.createMarshaller();
NamespacePrefixMapper prefixMapper = new MyPrefixMapperImpl();
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", prefixMapper);

The property name is going to be different for the Java6 version, but you get the idea.

Note that this is an internal JAXB implementation class, so there's no guarantee it'll be there in future versions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文