2008-09-23 13 views
35

का उपयोग कर रहा एक XML फ़ाइल है कि इस तरह शुरू होता है एक्सएमएल फाइल में नामस्थान पुनः प्राप्त करने के:कैसे Xpath

<Elements name="Entities" xmlns="XS-GenerationToolElements"> 

मैं इन फ़ाइलों का एक बहुत खोलने के लिए होगा। इनमें से प्रत्येक के पास एक अलग नामस्थान है लेकिन एक समय में केवल एक नामस्थान होगा (मुझे कभी भी एक एक्सएमएल फ़ाइल में परिभाषित दो नामस्थान नहीं मिलेगा)।

XPath का उपयोग करके मैं नामस्थान प्रबंधक को दिया गया नामस्थान जोड़ने का एक स्वचालित तरीका चाहता हूं। अभी तक, मैं केवल xml फ़ाइल को पार्स करके नामस्थान प्राप्त कर सकता हूं लेकिन मेरे पास XPathNavigator इंस्टेंस है और इसमें नामस्थान प्राप्त करने के लिए एक अच्छा और साफ तरीका होना चाहिए, है ना?

- या -

यह देखते हुए कि मैं केवल एक नाम स्थान है, किसी भी तरह XPath केवल एक ही है कि एक्सएमएल में मौजूद है का उपयोग करें, इस प्रकार हमेशा नाम स्थान जोड़कर कोड को अव्यवस्थित से परहेज करते हैं।

+0

क्या ये हमेशा डिफ़ॉल्ट नामस्थान में हैं? या आपके पास कभी है: xmlns: myns = "namepace-uri" क्या आप फ़ाइलों को पूरी तरह से एक DOM दस्तावेज़ में पढ़ते हैं या XmlValidatingReader जैसे किसी का उपयोग करके पार्स पढ़ते हैं? – Kev

+0

वे हमेशा डिफ़ॉल्ट नामस्थान में रहते हैं। मैं पूरी तरह से फाइल नहीं पढ़ रहा हूं, क्योंकि मैं इस मामले में फंस गया हूं; मुझे लगता है कि जब आप "डीओएम दस्तावेज़ में या XmlValidatingReader की तरह कुछ का उपयोग करके पार्स" पूछते हैं तो मैं पूरी तरह समझ नहीं पा रहा हूं; मैं XML पढ़ने के लिए केवल XPath का उपयोग करूंगा; क्या यह बुरा है? –

उत्तर

76

ऐसी कुछ तकनीकें हैं जिनका आप प्रयास कर सकते हैं; जो आप उपयोग करते हैं, वह इस बात पर निर्भर करेगा कि आपको दस्तावेज़ से बाहर निकलने के लिए कितनी जानकारी चाहिए, आप कितना कठोर होना चाहते हैं, और आप जिस XPath कार्यान्वयन का उपयोग कर रहे हैं उसके अनुरूप है।

किसी विशेष उपसर्ग से जुड़े नामस्थान यूआरआई प्राप्त करने का एक तरीका namespace:: धुरी का उपयोग कर रहा है। यह आपको एक नामस्थान नोड देगा जिसका नाम उपसर्ग है और जिसका मूल्य नामस्थान यूआरआई है। उदाहरण के लिए, यदि आप डिफ़ॉल्ट नाम स्थान यूआरआई मिल सकता है पथ का उपयोग कर दस्तावेज़ तत्व पर:

/*/namespace::*[name()=''] 

आप उपयोग करने के लिए है कि अपने XPathNavigator के लिए नाम स्थान संघों की स्थापना के लिए सक्षम हो सकता है। चेतावनी दी जानी चाहिए कि namespace:: अक्ष XPath 1.0 के उन कोनों में से एक है जिसे हमेशा लागू नहीं किया जाता है।

उस नामस्थान को प्राप्त करने का दूसरा तरीका यूआरआई दस्तावेज़ तत्व पर namespace-uri() फ़ंक्शन का उपयोग करना है (जिसे आपने हमेशा कहा है कि उस नामस्थान में होगा)। अभिव्यक्ति:

namespace-uri(/*) 

आपको वह नामस्थान देगा।

एक विकल्प उस नामस्थान के साथ उपसर्ग को जोड़ने के बारे में भूलना होगा, और बस अपना पथ नाम-मुक्त बनाएं। आप local-name() फ़ंक्शन का उपयोग कर ऐसा कर सकते हैं जब भी आपको उस तत्व का संदर्भ लेना पड़ेगा जिसका नामस्थान आप नहीं जानते हैं।

//*[local-name() = 'Element'] 

आप एक कदम आगे जाने के लिए और दस्तावेज़ तत्व में से एक के खिलाफ तत्व का नाम स्थान यूआरआई का परीक्षण, यदि आप वास्तव में चाहते थे सकता है::

//*[local-name() = 'Element' and namespace-uri() = namespace-uri(/*)] 

एक अंतिम विकल्प, यह देखते हुए कि उदाहरण के लिए नेमस्पेस का मतलब आपके लिए कुछ भी नहीं है, यह आपके एक्सएमएल को ऐसे फ़िल्टर के माध्यम से चलाने के लिए होगा जो नेमस्पेस को स्ट्रिप्स करता है। तब आपको अपने XPath में उनके बारे में चिंता करने की ज़रूरत नहीं होगी। ऐसा करने का सबसे आसान तरीका नियमित अभिव्यक्ति के साथ xmlns विशेषता को निकालना होगा, लेकिन यदि आप एक ही समय में अन्य tidying करना चाहते हैं तो आप कुछ और जटिल कर सकते हैं।

+2

धन्यवाद आपके विस्तृत उत्तर के लिए धन्यवाद, ऐसा लगता है कि मुझे –

+1

को एक अनुकरणीय उत्तर देने के लिए अभी तक कोई प्रतिष्ठा नहीं है, धन्यवाद, जेनीटी – kostja

+0

दूसरी विधि QXmlQuery के साथ Qt में अच्छी तरह से काम करती है। बहुत बढ़िया जवाब। –

4

दुर्भाग्य से, XPath में "डिफ़ॉल्ट नामस्थान" की कोई अवधारणा नहीं है। आपको XPath संदर्भ के साथ उपसर्गों के साथ नामस्थानों को पंजीकृत करने की आवश्यकता है, और फिर उन XPf अभिव्यक्तियों में उन उपसर्गों का उपयोग करें। इसका मतलब बहुत वर्बोज़ xpath के लिए है, लेकिन यह XPath 1 की मूल कमी है। जाहिर है XPath 2 इसे संबोधित करेगा, लेकिन अभी इसका कोई उपयोग नहीं है।

मेरा सुझाव है कि आप नेमस्पेस के लिए प्रोग्रामेटिक रूप से अपने एक्सएमएल दस्तावेज़ की जांच करें, XPath संदर्भ में उपसर्ग के साथ नेमस्पेस को संबद्ध करें, फिर xpath अभिव्यक्तियों में उपसर्ग का उपयोग करें।

+0

ऐसा लगता है कि इसे उस पर उबालना होगा ..! धन्यवाद –

+0

मुझे संदेह है कि यह वास्तविक जवाब है क्योंकि ऐसा लगता है कि XPath में नेमस्पेस पूछने की अतिरिक्त जटिलताओं से बचने की इच्छा थी। उचित उत्तर स्वीकार करने के लिए मत भूलना। – AnthonyWJones

10

यह 40 लाइन xslt परिवर्तन किसी दिए गए XML दस्तावेज़ में नामस्थान के बारे में सभी उपयोगी जानकारी प्रदान करता:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ext="http://exslt.org/common" 
    exclude-result-prefixes="ext" 
> 

<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:strip-space elements="*"/> 

<xsl:key name="kNsByNsUri" match="ns" use="@uri"/> 

<xsl:variable name="vXmlNS" 
    select="'http://www.w3.org/XML/1998/namespace'"/> 

<xsl:template match="/"> 
    <xsl:variable name="vrtfNamespaces"> 
    <xsl:for-each select= 
     "//namespace::* 
      [not(. = $vXmlNS) 
      and 
       . = namespace-uri(..) 
      ]"> 
     <ns element="{name(..)}" 
      prefix="{name()}" uri="{.}"/> 
    </xsl:for-each> 
    </xsl:variable> 

    <xsl:variable name="vNamespaces" 
    select="ext:node-set($vrtfNamespaces)/*"/> 

    <namespaces> 
      <xsl:for-each select= 
      "$vNamespaces[generate-id() 
         = 
         generate-id(key('kNsByNsUri',@uri)[1]) 
         ]"> 
      <namespace uri="{@uri}"> 
       <xsl:for-each select="key('kNsByNsUri',@uri)/@element"> 
       <element name="{.}" prefix="{../@prefix}"/> 
       </xsl:for-each> 
      </namespace> 
      </xsl:for-each> 
    </namespaces> 
</xsl:template> 

जब निम्नलिखित XML दस्तावेज़ पर लागू:

<a xmlns="my:def1" xmlns:n1="my:n1" 
    xmlns:n2="my:n2" xmlns:n3="my:n3"> 
    <b> 
    <n1:d/> 
    </b> 
    <n1:c> 
    <n2:e> 
     <f/> 
    </n2:e> 
    </n1:c> 
    <n2:g/> 
</a> 

वांछित परिणाम उत्पन्न होता है:

<namespaces> 
    <namespace uri="my:def1"> 
     <element name="a" prefix=""/> 
     <element name="b" prefix=""/> 
     <element name="f" prefix=""/> 
    </namespace> 
    <namespace uri="my:n1"> 
     <element name="n1:d" prefix="n1"/> 
     <element name="n1:c" prefix="n1"/> 
    </namespace> 
    <namespace uri="my:n2"> 
     <element name="n2:e" prefix="n2"/> 
     <element name="n2:g" prefix="n2"/> 
    </namespace> 
</namespaces> 
+0

इसे कैसे लागू करें? –