2010-09-19 19 views
10

मैं बहु-नामस्थान XML दस्तावेज़ों को HTML में बदलने के लिए एक एक्सएसएलटी 1.0 स्टाइलशीट लिख रहा हूं। परिणाम में कुछ जगह पर HTML मैं दस्तावेज़ में होने वाले सभी नामस्थानों को सूचीबद्ध करना चाहता हूं।एक्सएसएलटी: सभी उपयोग किए गए नेमस्पेस की सूची कैसे प्राप्त करें

क्या यह संभावना है?

मैं

<xsl:for-each select="//*|//@*"> 
    <xsl:value-of select="namespace-uri(.)" /> 
</xsl:for-each> 

की तरह कुछ के बारे में सोचा लेकिन निश्चित रूप से मैं डुप्लिकेट के gazillions मिल चाहते हैं। इसलिए मुझे किसी भी तरह फ़िल्टर करना होगा, जो मैंने पहले ही मुद्रित किया है।

रिकर्सिव कॉलिंग टेम्पलेट्स काम करेंगे, लेकिन मैं अपने सिर को सभी तत्वों तक पहुंचने के तरीके को लपेट नहीं सकता।

एक्सेस करना //@xmlns:* सीधे, काम नहीं करता है, क्योंकि एक XPath के माध्यम से इस का उपयोग नहीं कर सकते हैं (एक xmlns: नाम स्थान के लिए किसी भी उपसर्ग बाध्य करने के लिए अनुमति नहीं है)।

+0

अच्छा प्रश्न (+1)। एक संक्षिप्त और कुशल समाधान के लिए मेरा जवाब देखें। :) –

+0

मैंने अभी अपने जवाब में एक एक्सएसएलटी 2.0 समाधान जोड़ा - बस पूर्णता के लिए। –

उत्तर

7

एक और:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="*"> 
     <xsl:param name="pNamespaces" select="'&#xA;'"/> 
     <xsl:variable name="vNamespaces"> 
      <xsl:variable name="vMyNamespaces"> 
       <xsl:value-of select="$pNamespaces"/> 
       <xsl:for-each select="namespace::* 
             [not(contains(
               $pNamespaces, 
               concat('&#xA;',.,'&#xA;')))]"> 
        <xsl:value-of select="concat(.,'&#xA;')"/> 
       </xsl:for-each> 
      </xsl:variable> 
      <xsl:variable name="vChildsNamespaces"> 
       <xsl:apply-templates select="*[1]"> 
        <xsl:with-param name="pNamespaces" 
             select="$vMyNamespaces"/> 
       </xsl:apply-templates> 
      </xsl:variable> 
      <xsl:value-of select="concat(substring($vMyNamespaces, 
                1 div not(*)), 
             substring($vChildsNamespaces, 
                1 div boolean(*)))"/> 
     </xsl:variable> 
     <xsl:variable name="vFollowNamespaces"> 
      <xsl:apply-templates select="following-sibling::*[1]"> 
       <xsl:with-param name="pNamespaces" select="$vNamespaces"/> 
      </xsl:apply-templates> 
     </xsl:variable> 
     <xsl:value-of 
      select="concat(substring($vNamespaces, 
             1 div not(following-sibling::*)), 
          substring($vFollowNamespaces, 
             1 div boolean(following-sibling::*)))"/> 
    </xsl:template> 
</xsl:stylesheet> 

आउटपुट (Dimitre के इनपुट नमूना के साथ):

http://www.w3.org/XML/1998/namespace 
mynamespace 
mynamespace2 
mynamespace3 

संपादित: इसके अलावा इस XPath अभिव्यक्ति:

//*/namespace::*[not(. = ../../namespace::*|preceding::*/namespace::*)] 

सबूत के रूप में, इस स्टाइलशीट:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:template match="/"> 
     <xsl:for-each select="//*/namespace::* 
            [not(. = ../../namespace::*| 
               preceding::*/namespace::*)]"> 
      <xsl:value-of select="concat(.,'&#xA;')"/> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

आउटपुट:

http://www.w3.org/XML/1998/namespace 
mynamespace 
mynamespace2 
mynamespace3 

संपादित करें 4: दो पास परिवर्तन के रूप में ही कुशल।

यह स्टाइलशीट:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:key name="kElemByNSURI" 
      match="*[namespace::*[not(. = ../../namespace::*)]]" 
       use="namespace::*[not(. = ../../namespace::*)]"/> 
    <xsl:template match="/"> 
     <xsl:for-each select= 
      "//namespace::*[not(. = ../../namespace::*)] 
          [count(..|key('kElemByNSURI',.)[1])=1]"> 
      <xsl:value-of select="concat(.,'&#xA;')"/> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

आउटपुट:

http://www.w3.org/XML/1998/namespace 
mynamespace 
mynamespace2 
mynamespace3 

संपादित 5: आप namespace कुल्हाड़ी कार्यान्वयन (TransforMiix की तरह) के बिना एक XSLT प्रोसेसर के साथ काम कर रहे हैं, तो आप केवल निकाल सकते हैं नामस्थान वास्तव में इस स्टाइलशीट के साथ प्रयोग किया जाता है:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:key name="kElemByNSURI" match="*|@*" use="namespace-uri()"/> 
    <xsl:template match="/"> 
     <xsl:for-each select= 
      "(//*|//@*)[namespace-uri()!=''] 
         [count(.|key('kElemByNSURI',namespace-uri())[1])=1]"> 
      <xsl:value-of select="concat(namespace-uri(),'&#xA;')"/> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

ट्रांसफोर्मिक्स आउटपुट:

mynamespace2 
+0

@Alejandro: सही उत्तर के लिए +1। हम दोनों जानते हैं कि 'xxx: node-set()' का उपयोग अधिक अक्षम समाधान में नहीं है :) –

+0

+1 उन समाधानों के लिए है जो एक्सटेंशन से बचाते हैं। मैं उस पर काम कर रहा था जिसने नामस्थान यूआरआई जमा करने के लिए एक स्ट्रिंग का इस्तेमाल किया था, लेकिन आपका शायद बेहतर है। – LarsH

+0

इस समाधान के लिए धन्यवाद! मैंने 'नेमस्पेस ::' अक्ष को याद किया, और मैं हमेशा * '(विशेष रूप से जब इसका उपयोग वास्तव में मूल्यवान होगा) के बारे में भूल जाता है। – Boldewyn

5

यह परिवर्तन:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="text"/> 
<xsl:template match="/"> 
    <xsl:for-each select= 
    "//namespace::*[not(. = ../../namespace::*)]"> 
    <xsl:value-of select="concat(.,'&#xA;')"/> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

जब इस XML दस्तावेज़ पर लागू:

http://www.w3.org/XML/1998/namespace 
mynamespace 
mynamespace2 
mynamespace3 
:

<authors xmlns:user="mynamespace"> 
    <?ttt This is a PI ?> 
    <author xmlns:user2="mynamespace2"> 
    <name idd="VH">Victor Hugo</name> 
    <user2:name idd="VH">Victor Hugo</user2:name> 
    <nationality xmlns:user3="mynamespace3">French</nationality> 
    </author> 
</authors> 

चाहता था, सही परिणाम का उत्पादन

अद्यतन:

<authors xmlns:user="mynamespace"> 
    <?ttt This is a PI ?> 
    <author xmlns:user2="mynamespace2"> 
    <name idd="VH">Victor Hugo</name> 
    <user2:name idd="VH">Victor Hugo</user2:name> 
    <nationality xmlns:user3="mynamespace3">French</nationality> 
    </author> 
    <t xmlns:user2="mynamespace2"/> 
</authors> 

नाम स्थान "mynamespace2" उत्पादन में दो बार का उत्पादन किया जाएगा:

@svick टिप्पणी की है के रूप में, इसके बाद के संस्करण समाधान अभी भी कभी-कभी इस तरह के निम्नलिखित XML दस्तावेज़ के साथ के रूप में डुप्लिकेट नामस्थान का उत्पादन करेगा ।

निम्नलिखित परिवर्तन फिक्स इस मुद्दे:

http://www.w3.org/XML/1998/namespace 
mynamespace 
mynamespace2 
mynamespace3 

:

<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 method="text"/> 

<xsl:key name="kNSbyURI" match="n" use="."/> 

<xsl:template match="/"> 
    <xsl:variable name="vrtfNS"> 
     <xsl:for-each select= 
     "//namespace::*[not(. = ../../namespace::*)]"> 
     <n><xsl:value-of select="."/></n> 
     </xsl:for-each> 
    </xsl:variable> 

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

    <xsl:for-each select= 
    "$vNS[generate-id() 
     = 
      generate-id(key('kNSbyURI',.)[1]) 
     ]"> 
    <xsl:value-of select="concat(., '&#xA;')"/> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

जब इस बदलाव से ऊपर XML दस्तावेज़ पर लागू किया जाता है, यह दस्तावेज़ में केवल सभी अद्वितीय नामस्थान का उत्पादन भाग II: एक एक्सएसएलटी 2.0 समाधान

एक्सएसएलटी 2.0 समाधान एक साधारण XPath 2 है।0 एक लाइनर:

विस्तार कार्यों के बिना
distinct-values(//namespace::*) 
+0

यह सही ढंग से काम नहीं करता है जब दो स्थानों पर एक नेमस्पेस परिभाषित किया जाता है: ''। – svick

+0

@svick: अच्छा पकड़ो! मैंने अब इस मुद्दे को ठीक कर दिया है। –

+0

उत्तर के लिए धन्यवाद! मैं एक गैर-EXSLT समाधान की तलाश में था, क्योंकि मुझे टेम्पलेट को क्रॉस-इंजन निष्पादन योग्य होने की आवश्यकता है। लेकिन अगर मैं इसे भविष्य में कभी-कभी एक्सएसएलटी 2.0 में फिर से लिखूंगा, तो मैं नोड-सेट समाधान के लिए वापस आ रहा हूं। – Boldewyn

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