web-dev-qa-db-ja.com

JAXB:xmlns:xsiの名前空間定義の繰り返しを回避する方法

@XmlJavaTypeAdapterを使用して、タイプPersonのオブジェクトを個人のUUIDのみを含むタイプPersonRefのオブジェクトに置き換えるJAXBセットアップがあります。これは完全に正常に機能します。ただし、生成されたXMLは同じ名前空間を再宣言します(xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance")使用するたびに。これは一般的には問題ありませんが、正しく感じられません。

ドキュメントの冒頭でxmlns:xsiを宣言するようにJAXBを構成するにはどうすればよいですか?名前空間宣言をルート要素に手動で追加できますか?

これが私が達成したいことの例です:

現在:

<person uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a">
    <relation type="CHILD"> 
        <to xsi:type="personRef" uuid="56a930c0-5499-467f-8263-c2a9f9ecc5a0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
    </relation> 
    <relation type="CHILD"> 
        <to xsi:type="personRef" uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
    </relation>
    <!-- SNIP: some more relations -->
</person>

ウォンテッド:

<person uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <relation type="CHILD"> 
        <to xsi:type="personRef" uuid="56a930c0-5499-467f-8263-c2a9f9ecc5a0"/> 
    </relation> 
    <relation type="CHILD"> 
        <to xsi:type="personRef" uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a"/> 
    </relation>
    <!-- SNIP: some more relations -->
</person>
20
sfussenegger

あなたはコードでそれを行うことができます:

marshaller.setProperty("com.Sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
                @Override
                public String[] getPreDeclaredNamespaceUris() {
                    return new String[] { 
                        XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI
                    };
                }

                @Override
                public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                    if (namespaceUri.equals(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI))
                        return "xsi";
                    if (namespaceUri.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI))
                        return "xs";
                    if (namespaceUri.equals(WellKnownNamespace.XML_MIME_URI))
                        return "xmime";
                    return suggestion;

                }
            });
6
Dany

thatきれいではありませんが、ルート要素に空のschemaLocationを追加できます。

marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "");
17
msp

JAXBカスタマイズ名前空間マッパーの問題 のように見えます

JAXB 1.0を使用してXMLドキュメントをマーシャリングすると、マーシャリングのプロセスを制御するJAXBオブジェクトであるMarshallerオブジェクトが、結果のXMLドキュメントに名前空間宣言を提供します。マーシャラーは、冗長に見える多くの名前空間宣言を生成することがあります。次に例を示します。

_   <?xml version="1.0"?>
   <root>
      <ns1:element xmlns:ns1="urn:foo"> ... </ns1:element>
      <ns2:element xmlns:ns2="urn:foo"> ... </ns2:element>
      <ns3:element xmlns:ns3="urn:foo"> ... </ns3:element>
   </root>
_

JAXB2.0はこの動作を変更します。 JAXB 2.0(またはそれ以降)を使用してXMLドキュメントをマーシャリングする場合、マーシャラーは静的に既知のすべての名前空間URI(Uniform Resource Identifiers)、つまりJAXBアノテーションで要素名または属性名として使用されるURIを宣言します。

JAXBは、XMLドキュメントの途中で追加の名前空間を宣言することもあります。たとえば、属性または要素の値として使用される修飾名(QName)に新しい名前空間URIが必要な場合、またはドキュメントオブジェクトモデル(コンテンツツリーのDOM)ノードには、新しい名前空間URIが必要です。この動作により、自動生成された名前空間プレフィックスを持つ多くの名前空間宣言を持つXMLドキュメントが生成される場合があります。

問題は、ns1、ns2、ns3などの自動生成された名前空間プレフィックスがユーザーフレンドリーではないことです。これらは通常、マーシャリングされたXMLを理解するのに役立ちません。

幸い、JAXB 2.0(またはそれ以降)は、マーシャリングに役立つ名前空間プレフィックスを指定するために使用できる _com.Sun.xml.bind.marshaller.NamespacePrefixMapper_ という名前のサービスプロバイダーインターフェイス(SPI)を提供します。

JAXBSampleプログラムが最初にXMLドキュメントをマーシャルするとき、NamespacePrefixMapperクラスを使用せずにマーシャルします。その結果、マーシャラーは名前空間プレフィックス(この場合はns2)を自動的に生成します。

_   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <ns2:JustAnElement xmlns:ns2="a">
       <foo>true</foo>
   </ns2:JustAnElement>
_

名前空間の繰り返しを回避する構成の例:

JAXBSampleプログラムによって実行される2番目のマーシャリングは、次のようにNamespacePrefixMapperクラスを使用します。

_   NamespacePrefixMapper m = new PreferredMapper();
               marshal(jc, e, m);

   public static class PreferredMapper extends NamespacePrefixMapper {
           @Override
           public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
               return "mappedNamespace" + namespaceUri;
           }
       }
_

PreferredMapperクラスのgetPreferredPrefix()メソッドは、優先プレフィックスを返します。この場合は、マーシャリングされたXMLのルート要素で宣言されるmappedNamespaceaです。

_   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <mappedNamespacea:JustAnElement xmlns:mappedNamespacea="a">
       <foo>true</foo>
   </mappedNamespacea:JustAnElement>
_
9
VonC

mavenを使用している場合は、これをpomに追加するだけです。

<dependency>
            <groupId>com.Sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.2.2</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>

上記の例で定義されているように注釈を構成する場合は、PreferredMapperは必要ありません。 package-info.javeファイルがありますが、次のように構成されています。

@javax.xml.bind.annotation.XmlSchema(
        namespace = "mylovelynamespace1", 
        xmlns = {
                    @javax.xml.bind.annotation.XmlNs(prefix = "myns1", namespaceURI = "mylovelynamespace1"),
                    @javax.xml.bind.annotation.XmlNs(prefix = "myns2", namespaceURI = "mylovelynamespace2")
                }, 
                elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.mylovelycompanyname.package;
3
Miguel de Melo

これは私がウェブで見つけた最良の答えです。

JAXBElementの宣言された型が値の型と一致しないため、xsi:type宣言が作成されている可能性があります。

ObjectFactoryに正しいJAXBElementのc​​reateメソッドがある場合は、それを使用する必要があります。これは、QNameとタイプ情報の両方を正しく入力する必要があるためです。それ以外の場合は、JAXBElementの宣言された型(2番目のコンストラクターarg)をString.classではなくCommentType.Commentに設定してみます(これがcommentTestの型であると仮定します)。

ソース: http://www.Java.net/forum/topic/glassfish/metro-and-jaxb/how-do-i-remove-namespace-declarations-child-elements

所有者:cbrettin

2
Aguid

名前空間は一度だけ書き込むことができます。 XMLStreamWriterのプロキシクラスとpackage-info.Javaが必要になります。次に、コードで次のことを行います。

StringWriter stringWriter = new StringWriter();
XMLStreamWriter writer = new Wrapper((XMLStreamWriter) XMLOutputFactory
                                                               .newInstance().createXMLStreamWriter(stringWriter));
JAXBContext jaxbContext = JAXBContext.newInstance(Collection.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
jaxbMarshaller.marshal(books, writer);
System.out.println(stringWriter.toString());

プロキシクラス(重要なメソッドは「writeNamespace」です):

            class WrapperXMLStreamWriter implements XMLStreamWriter {

                   private final XMLStreamWriter writer;

                   public WrapperXMLStreamWriter(XMLStreamWriter writer) {
                       this.writer = writer;
                   }

                     //keeps track of what namespaces were used so that not to 
                     //write them more than once
                   private List<String> namespaces = new ArrayList<String>();

                   public void init(){
                       namespaces.clear();
                   }

                   public void writeStartElement(String localName) throws XMLStreamException {
                       init();
                       writer.writeStartElement(localName);

                   }

                   public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
                       init();
                       writer.writeStartElement(namespaceURI, localName);
                   }

                   public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
                       init();
                       writer.writeStartElement(prefix, localName, namespaceURI);
                   }

                   public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
                       if(namespaces.contains(namespaceURI)){ 
                           return;
                       }
                       namespaces.add(namespaceURI);
                       writer.writeNamespace(prefix, namespaceURI);
                   }

    // .. other delegation method, always the same pattern: writer.method() ...

}

package-info.Java:

@XmlSchema(elementFormDefault=XmlNsForm.QUALIFIED, attributeFormDefault=XmlNsForm.UNQUALIFIED ,
        xmlns = { 
        @XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema-instance", prefix = "xsi")})
package your.package;

import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
2
Amio.io

次のようにして、nsPrefixマッピングを追加します。

marshaller.setNamespaceMapping("myns","urn:foo");

0
Eason Xiao

これはXMLであるため、DOMまたはXSLTを使用して出力を処理し、複数の名前空間参照を取り除くことができます。

0