2010-11-19 9 views
5

मैं कुछ मनमानी एक्सएमएल शामिल करने के लिए एक जेएक्सबी मार्शलिंग ऑपरेशन के लिए आउटपुट स्ट्रीम को संशोधित करना चाहता हूं। स्थिति को स्पष्ट करने के लिए यहां एक उदाहरण दिया गया है।मनमानी इनलाइन एक्सएमएल को शामिल करने के लिए मैं जेएक्सबी मार्शलिंग आउटपुट स्ट्रीम को कैसे संशोधित कर सकता हूं?

@XmlRootElement(name="Product") 
public class Product { 

    @XmlElement(name="CommonProperty") 
    private String commonProperty="Something"; 

    @XmlElement(name="ExtraXml") 
    private String extraXml="Something extra"; 

} 

कौन सा आम तौर पर इस में मार्शल होगा:: अब

<Product> 
    <CommonProperty>Something</CommonProperty> 
    <ExtraXml>Something else</ExtraXml> 
</Product> 

, क्या हुआ अगर extraXml क्षेत्र कुछ निहित

मैं JAXB एनोटेशन के साथ एक मनमाना Product डोमेन उद्देश्य यह है कि वर्तमान में इस तरह दिखना है अतिरिक्त एक्सएमएल (मनमानी जटिलता का) जिसे अंतिम मार्शल परिणाम के साथ इनलाइन शामिल किया जाना था?

कहो, extraXml निहित "<abc><def>Something extra</def></abc>", मैं वास्तव में एक समाधान है कि मुझे सक्षम Product की तरह मार्शल करने के लिए की तरह होगा इस (वैकल्पिक स्वरूपण):

<Product> 
    <CommonProperty>Something</CommonProperty> 
    <abc> 
    <def>Something extra</def> 
    </abc> 
</Product> 

मैं this related question को देखा है, लेकिन यह काफी नहीं था जिसके परिणामस्वरूप मैं बाद में हूं, क्योंकि यह डोम सम्मिलन के बजाए एक समग्र स्वरूप परिवर्तन की दिशा में अधिक स्पष्ट लगता है।

extraXml संपत्ति चित्रण के लिए बस वहां है, इसे @XmlTransient या एक विशेष श्रेणी में चिह्नित किया जा सकता है। एकमात्र मानदंड यह है कि यह किसी भी तरह String प्राप्त कर सकता है जिसमें व्यक्ति Product मार्शल आउटपुट को जोड़ने के लिए पूरी तरह से मनमानी एक्सएमएल सामग्री शामिल है।

मुझे यह भी जिक्र करना चाहिए कि इससे आउटपुट के उपभोक्ता मनमानी सामग्री को ऐसे तरीके से पार्स करने में सक्षम हैं जो उन्हें उपयुक्त बनाता है। यहां का उद्देश्य सर्वर की तरफ प्रोसेसिंग को सरल बनाना है।

किसी भी मदद के लिए अग्रिम धन्यवाद।

उत्तर

6

आप अतिरिक्त एक्सएमएल को स्ट्रिंग के बजाय डोम नोड के रूप में प्रदर्शित कर सकते हैं।

अतिरिक्त एक्सएमएल संपत्ति को एक स्ट्रिंग के बजाय org.w3c.dom.Node होने के लिए बदलें, और इसे @XmlAnyElement के साथ एनोटेट करें।

import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAnyElement; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

import org.w3c.dom.Node; 

@XmlRootElement(name="Product") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Product { 

    @XmlElement(name="CommonProperty") 
    private String commonProperty="Something"; 

    @XmlAnyElement 
    private Node extraXml; 

} 

तो फिर तुम इस तरह के रूप में एक XML दस्तावेज umarshal जब:

<Product> 
    <CommonProperty>Something</CommonProperty> 
    <abc> 
    <def>Something extra</def> 
    </abc> 
</Product> 

निम्नलिखित कोड के साथ:

import java.io.File; 
import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(Product.class); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     File xml = new File("input.xml"); 
     Product product = (Product) unmarshaller.unmarshal(xml); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(product, System.out); 
    } 
} 

"अतिरिक्त एक्सएमएल" एक डोम नोड के रूप में रखा जाएगा।

+0

वादा करता है - क्या आप थोड़ा सा विस्तार कर सकते हैं? –

+0

@ गैरी, मैंने यह जवाब देने के लिए अपना जवाब अपडेट किया है कि यह @XmlAnyElement का उपयोग करके कैसे किया जा सकता है। आपके बड़े अपडेट के लिए –

+1

+1 - यह एक बड़ी मदद है (और आज 3K तोड़ने पर बधाई)। यदि आपको कोई फर्क नहीं पड़ता तो एक आखिरी बिट है। Marshalling की शुरुआत में, मेरे पास केवल 'extraXml' एक स्ट्रिंग के रूप में है और' नए उत्पाद() 'द्वारा बनाए गए' उत्पाद' का एक उदाहरण है। क्या नोड को इस तरीके से निर्दिष्ट करने का कोई तरीका है कि जेएक्सबी मार्शल से खुश है? –

5

Blaise Doughan की सहायता के साथ यहां अंतिम समाधान है जिसे मैंने तय किया है। इसमें कुछ अतिरिक्त प्रदर्शन कोड शामिल हैं जो दूसरों को इस स्थिति में ढूंढने में मदद कर सकते हैं।

कक्षाएं

productlist (एक नई रैपिंग वर्ग को दिखाने के लिए कि यह कैसे एक से अधिक उत्पाद प्रविष्टियों के लिए काम करता है)

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlElementWrapper; 
import javax.xml.bind.annotation.XmlRootElement; 
import java.util.ArrayList; 
import java.util.List; 

@XmlRootElement(name="ProductList") 
public class ProductList { 

    @XmlElementWrapper(name="Products") 
    @XmlElement(name="Product") 
    public List<Product> products = new ArrayList<Product>(); 

} 

उत्पाद (ब्लेज के संशोधनों के साथ)

import org.w3c.dom.Node; 

import javax.xml.bind.annotation.*; 

@XmlRootElement(name="Product") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Product { 

    @XmlElement(name="CommonProperty") 
    public String commonProperty="Something"; 

    @XmlAnyElement 
    public Node extraXml; 

} 

मुख्य (कुछ प्रदर्शन कोड)

import org.w3c.dom.Document; 
import org.xml.sax.InputSource; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 
import javax.xml.parsers.DocumentBuilderFactory; 
import java.io.StringReader; 

public class Main { 

    public static void main(String[] args) throws Exception { 

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 

    // Build some arbitrary extra XML and prepare an InputStream 
    String fragment1 = "<abc><def>Some extra 1</def></abc>"; 
    String fragment2 = "<ghi><jkl>Some extra 2</jkl></ghi>"; 
    Document document1 = factory.newDocumentBuilder().parse(new InputSource(new StringReader(fragment1))); 
    Document document2 = factory.newDocumentBuilder().parse(new InputSource(new StringReader(fragment2))); 

    Product product1 = new Product(); 
    product1.commonProperty = "Hello 1"; 
    product1.extraXml=document1.getFirstChild(); 

    Product product2 = new Product(); 
    product2.commonProperty = "Hello 2"; 
    product2.extraXml=document2.getFirstChild(); 

    ProductList productList = new ProductList(); 
    productList.products.add(product1); 
    productList.products.add(product2); 

    JAXBContext jc = JAXBContext.newInstance(ProductList.class, Product.class); 
    Marshaller marshaller = jc.createMarshaller(); 
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
    marshaller.marshal(productList, System.out); 

    } 
} 

अंतिम आउटपुट:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ProductList> 
    <Products> 
     <Product> 
      <CommonProperty>Hello 1</CommonProperty> 
      <abc> 
       <def>Some extra 1</def> 
      </abc> 
     </Product> 
     <Product> 
      <CommonProperty>Hello 2</CommonProperty> 
      <ghi> 
       <jkl>Some extra 2</jkl> 
      </ghi> 
     </Product> 
    </Products> 
</ProductList> 

परिणाम!

लेकिन यह JBoss में काम नहीं करता ...

आप JBoss 4.2.3.GA में ऊपर की कोशिश या 4.3 आप पा सकते हैं कि आप एक

class com.sun.org.apache.xerces.internal.dom.DocumentFragmentImpl nor any of its super class is known to this context. 

अपवाद मिलता है रिपोर्ट किया जा रहा है। JDoss lib और /lib/endorsed फ़ोल्डरों में जावा META-INF/Services ओवरराइड सुविधा का उपयोग करके xercesImpl.jar के कारण यह संभवतः (संभवतः) आंतरिक कक्षाओं का उपयोग करके जेडीके को मारने से रोकने के लिए ओवरराइड सुविधा का उपयोग कर रहा है। आप सीधे निम्नलिखित दृष्टिकोण का उपयोग कर एक वैकल्पिक DocumentBuilderFactory निर्दिष्ट करने की आवश्यकता हो सकता है:

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance("oracle.xml.jaxp.JXDocumentBuilderFactory", this 
     .getClass().getClassLoader()); 

ओरेकल कार्यान्वयन इन मुद्दों को कम करने, शायद इसलिए क्योंकि यह JAXB संदर्भ में डोम नोड कक्षाओं के बारे में जागरूकता रहता है लगता है। ये वर्ग xdb.jar और xmlparserv2.jar में पाए जाते हैं ओरेकल क्लाइंट के साथ भेज दिया गया।

उम्मीद है कि यह मदद करता है।

संबंधित मुद्दे