2013-07-18 3 views
6

संरक्षित करती है मैं एक जावा प्रोग्राम लिख रहा हूं जो एक एक्सएमएल फ़ाइल पढ़ता है, कुछ संशोधन करता है, और एक्सएमएल वापस लिखता है।जावा एक्सएमएल लाइब्रेरी जो विशेषता ऑर्डर

मानक जावा एक्सएमएल डोम एपीआई का उपयोग करके, गुणों का क्रम संरक्षित नहीं है। है कि, अगर मैं इस तरह के रूप में एक इनपुट फ़ाइल है:

<person last_name="lederrey" first_name="john"/> 

यह सही है, क्योंकि XML विवरण कहना है कि आदेश विशेषता महत्वपूर्ण नहीं है:

<person first_name="john" last_name="lederrey"/> 

मैं के रूप में कोई आउटपुट फ़ाइल मिल सकता है।

हालांकि, मेरे प्रोग्राम को विशेषताओं, के क्रम को संरक्षित करने की आवश्यकता है ताकि कोई व्यक्ति आसानी से इनपुट और आउटपुट दस्तावेज़ को एक diff टूल से तुलना कर सके। Order of XML attributes after DOM processing

हालांकि, इस, मेरे मामले के लिए काम नहीं करता है क्योंकि परिवर्तन मैं एक नोड में क्या करने की जरूरत निर्भर कर सकते हैं:

एक यह है कि के लिए समाधान SAX (डोम के बजाय) के साथ दस्तावेज़ पर कार्रवाई करने के लिए है पूरे दस्तावेज़ पर एक XPATH अभिव्यक्ति पर। तो, सबसे सरल बात यह है कि एक्सएमएल लाइब्रेरी मानक जावा डॉम लिब के समान ही होगी, अपवाद के साथ कि यह प्रेसेवर गुण ऑर्डर देता है।

क्या ऐसी कोई पुस्तकालय है?

ps: कृपया, इस बात पर चर्चा से बचें कि मुझे विशेषता आदेश सुरक्षित रखना चाहिए या नहीं। यह एक बहुत ही रोचक चर्चा है, लेकिन यह इस सवाल का मुद्दा नहीं है।

+0

क्या आप डोम को यादृच्छिक विशेषता आदेश देते हैं यदि आप इनपुट को उसी तरह जोड़ते हैं (पाठ्यक्रम के मूल्यों को छोड़कर)? यह आपको वह आदेश नहीं दे सकता है जो आप चाहते हैं, लेकिन यह अजीब होगा अगर यह आपको एक यादृच्छिक आदेश देता है। मेरा मतलब है कि आदेश निर्दिष्ट नहीं किया जा सकता है, लेकिन इसमें कुछ तर्क होगा ... –

+0

मुझे लगता है कि शायद कोई पुस्तकालय नहीं है जो आपको आपके स्रोत XML फ़ाइल में विशेषताओं का क्रम बताता है। हालांकि, आप आउटपुट को नियंत्रित करने पर विचार कर सकते हैं, ताकि आप लिखित विशेषताओं को हमेशा एक ही परिभाषित क्रम में बना सकें (उदाहरण के लिए नाम से क्रमबद्ध)। – obecker

+0

@obecker, मेरे पास इनपुट xml फ़ाइल पर नियंत्रण नहीं है, इसलिए इनपुट xml पर विशेषताओं का क्रम अज्ञात है, और मैं ऑर्डर को मजबूर नहीं कर सकता। –

उत्तर

-1

आप डोम का उपयोग कर सकते हैं नहीं है, लेकिन आप SAX का उपयोग कर सकते हैं, या XPath का उपयोग कर जाएँ इस उत्तर बच्चों की क्वेरी https://stackoverflow.com/a/3728241/2598693

+0

ओपी पहले से ही कहा है कि यह जवाब उसके मामले में काम नहीं करता है। – mzjn

1

इसे दो बार कार्य करें:

दस्तावेज़ पढ़ें एक डोम पार्सर का उपयोग कर तो आप में संदर्भ, एक भंडार, यदि आप करेंगे।

फिर SAX का उपयोग करके इसे फिर से पढ़ें। उस बिंदु पर जहां आपको परिवर्तन करने की आवश्यकता है, आपको जो चाहिए उसे निर्धारित करने के लिए डीओएम संस्करण का संदर्भ लें, फिर SAX स्ट्रीम के बीच में आपको जो चाहिए उसे आउटपुट करें।

+0

यह एक विकल्प होगा, लेकिन यह तय करने के लिए कि क्या मुझे अद्यतन करना है या नहीं, वर्तमान नोड गधे में दर्द होगा (मुझे केवल एक तत्व को संशोधित करने की आवश्यकता है यदि उसके माता-पिता के पास कुछ विशिष्ट सामग्री वाले तीन बच्चे हैं, और इनमें से एक बच्चे वर्तमान नोड के बाद हो सकते हैं)। हालांकि, यह दृष्टिकोण ठीक रहेगा यदि SAX में वर्तमान स्थिति से अपने संबंधित डोम नोड में नेविगेट करने का कोई तरीका है। (उदाहरण के लिए, जब सैक्स मुझे बताता है कि यह एक नया नोड शुरू करता है, तो मुझे एक xpath अभिव्यक्ति प्राप्त करने में सक्षम होना चाहिए कि मैं डोम पर लागू कर सकता हूं और संबंधित नोड प्राप्त कर सकता हूं)। क्या इस तरह के एक सहायक समारोह पहले ही लागू किया गया है? –

+0

नोट, हालांकि, मुझे लगता है कि अगर हम मानक जावा डोम के समान लाइब्रेरी पाते हैं तो यह बहुत आसान होगा, जो ऑर्डर विशेषता को सुरक्षित रखता है। –

0

आपकी सर्वश्रेष्ठ शर्त मूल दस्तावेज़ उत्पन्न करने के लिए DOM के बजाय StAX का उपयोग करना होगा। एसएक्सएक्स आपको इन चीजों पर बहुत अच्छा नियंत्रण देता है और आपको आउटपुट स्ट्रीम में आउटपुट स्ट्रीम को क्रमशः आउटपुट स्ट्रीम करने की बजाय स्ट्रीम आउटपुट देता है।

1

पार्टी के लिए देर से आने वाले लोगों के लिए एक उत्तर: सैक्सन इन दिनों एक क्रमबद्धता विकल्प प्रदान करता है [1] जिसमें ऑर्डर आउटपुट होते हैं। यह इनपुट ऑर्डर को बरकरार नहीं रखता है (क्योंकि सैक्सन इनपुट ऑर्डर नहीं जानता है) लेकिन यह आपको नियंत्रित करने की अनुमति देता है, उदाहरण के लिए, आईडी विशेषता हमेशा पहले दिखाई देती है। और यह बहुत उपयोगी हो सकता है अगर एक्सएमएल को हाथ से संपादित किया जा रहा है; एक्सएमएल जिसमें "गलत" ऑर्डर में विशेषताएँ दिखाई देती हैं, मानव पाठक या संपादक के लिए बहुत ही विचलित हो सकती हैं।

यदि आप इसे एक diff प्रक्रिया के हिस्से के रूप में उपयोग कर रहे हैं तो आप दोनों फ़ाइलों को एक प्रक्रिया के माध्यम से रखना चाहते हैं जो उन्हें तुलना करने से पहले विशेषता आदेश को सामान्य करता है। हालांकि, फ़ाइलों की तुलना करने के लिए मेरा पसंदीदा दृष्टिकोण दोनों को पार्स करना और XPath गहरे-बराबर() फ़ंक्शन का उपयोग करना है; या डेल्टाएक्सएमएल जैसे एक विशेष उपकरण का उपयोग करने के लिए।

[1] सैक्सन: विशेषता-आदेश - http://www.saxonica.com/documentation/index.html#!extensions/output-extras/serialization-parameters

0

हम प्रति डेव वर्णन समान आवश्यकताओं था देखते हैं। एक समाधान जो काम करता था वह जावा प्रतिबिंब पर आधारित था।

विचार रनटाइम पर गुणों के लिए propOrder सेट करना है। हमारे मामले में APP_DATA तत्व जिसमें 3 विशेषताएँ हैं: ऐप, कुंजी, मान।

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "AppData", propOrder = { 
    "content" 
}) 
public class AppData { 

    @XmlValue 
    protected String content; 
    @XmlAttribute(name = "Value", required = true) 
    protected String value; 
    @XmlAttribute(name = "Name", required = true) 
    protected String name; 
    @XmlAttribute(name = "App", required = true) 
    protected String app; 
    ... 
} 

तो जावा प्रतिबिंब रनटाइम पर क्रम निर्धारित करने के लिए इस प्रकार के रूप में इस्तेमाल किया गया था: उत्पन्न AppData वर्ग "सामग्री" propOrder में और अन्य विशेषताओं में से कोई भी शामिल

 final String[] propOrder = { "app", "name", "value" }; 
     ReflectionUtil.changeAnnotationValue(
       AppData.class.getAnnotation(XmlType.class), 
       "propOrder", propOrder); 

     final JAXBContext jaxbContext = JAXBContext 
       .newInstance(ADI.class); 
     final Marshaller adimarshaller = jaxbContext.createMarshaller(); 
     adimarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, 
       true); 

     adimarshaller.marshal(new JAXBElement<ADI>(new QName("ADI"), 
       ADI.class, adi), new StreamResult(fileOutputStream)); 

changeAnnotationValue() था इस पोस्ट से उधार लिया:

: Modify a class definition's annotation string parameter at runtime

यहाँ (क्रेडिट @assylias में जाता है और @Balder) आपकी सुविधा के लिए विधि है

/** 
* Changes the annotation value for the given key of the given annotation to newValue and returns 
* the previous value. 
*/ 
@SuppressWarnings("unchecked") 
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue){ 
    Object handler = Proxy.getInvocationHandler(annotation); 
    Field f; 
    try { 
     f = handler.getClass().getDeclaredField("memberValues"); 
    } catch (NoSuchFieldException | SecurityException e) { 
     throw new IllegalStateException(e); 
    } 
    f.setAccessible(true); 
    Map<String, Object> memberValues; 
    try { 
     memberValues = (Map<String, Object>) f.get(handler); 
    } catch (IllegalArgumentException | IllegalAccessException e) { 
     throw new IllegalStateException(e); 
    } 
    Object oldValue = memberValues.get(key); 
    if (oldValue == null || oldValue.getClass() != newValue.getClass()) { 
     throw new IllegalArgumentException(); 
    } 
    memberValues.put(key,newValue); 
    return oldValue; 
} 

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

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