2012-02-28 14 views
6

में अनचाहे नेमस्पेस घोषणा मैं विशेष तत्व (subelement) का पहला बच्चा चुनना चाहता हूं, लेकिन इस बच्चे का नामस्थान माता-पिता के नामस्थान से अलग है। इसके अलावा, यह बच्चा किसी भी नामस्थान का हो सकता है।lxml XPath

xml = '''<root xmlns="default_ns"> 
    <subelement> 
     <!-- here we can have an element of any namespace --> 
     <some_prefix:a xmlns:some_prefix="some_namespace"> 
      <some_prefix:b/> 
     </some_prefix:a> 
    </subelement> 
</root>''' 
root = etree.fromstring(xml) 
evaluator = etree.XPathEvaluator(root, namespaces={'def':'default_ns'}) 
child = evaluator.evaluate('//def:subelement/child::*')[0] 
a_string = etree.tostring(child) 
print a_string 

यह देता है:

<some_prefix:a xmlns:some_prefix="some_namespace" xmlns="default_ns"> 
    <some_prefix:b/> 
</some_prefix:a> 

लेकिन क्या मैं प्राप्त करना चाहते हैं माता-पिता xmlns="default_ns" से नाम स्थान घोषणा के बिना बच्चा है:

<some_prefix:a xmlns:some_prefix="some_namespace"> 
    <some_prefix:b/> 
</some_prefix:a> 

उत्तर

0

डिमिट्रे पूरी तरह से समझाया गया कि क्यों नामस्थान विरासत में हैं और XSLT का उपयोग करके इसे कैसे छुटकारा पाएं।

मैंने गहराईcopy से अवांछित नामस्थान को हटाने के लिए उपयोग किया है।

from lxml import etree 
from copy import deepcopy 

xml = '''<root xmlns="default_ns"> 
    <subelement> 
     <!-- here we can have an element of any namespace --> 
     <some_prefix:a xmlns:some_prefix="some_namespace"> 
      <some_prefix:b/> 
     </some_prefix:a> 
    </subelement> 
</root>''' 
root = etree.fromstring(xml) 
evaluator = etree.XPathEvaluator(root, namespaces={'def':'default_ns'}) 
child = evaluator.evaluate('//def:subelement/child::*')[0] 
child = deepcopy(child) 
a_string = etree.tostring(child) 
print a_string 
1

लेकिन क्या मैं प्राप्त करना चाहते हैं के बिना बच्चा है पैरेंट xmlns = "default_ns" से नेमस्पेस घोषणा।

यह केवल एक XPath अभिव्यक्ति का मूल्यांकन करके प्राप्त करने के लिए संभव नहीं है।

एक्सएमएल में किसी भी तत्व को अपने सभी माता-पिता के नामस्थान नोड्स प्राप्त होता है, जब तक कि यह किसी विशेष नामस्थान को फिर से परिभाषित नहीं करता है।

इसका मतलब है कि some_prefix:a अपनी मूल (subelement), जो अपने आप शीर्ष तत्व root से यह एक ही डिफ़ॉल्ट नाम स्थान नोड विरासत से डिफ़ॉल्ट नाम स्थान "default_ns" इनहेरिट करती है।

XPath XML दस्तावेज़ों के लिए एक क्वेरी भाषा है। इस प्रकार, यह केवल नोड्स का चयन करने में मदद करता है, लेकिन किसी XPath अभिव्यक्ति का मूल्यांकन नामस्थान नोड्स सहित नोड्स को नष्ट या जोड़ता नहीं है।

इस वजह से, some_prefix:a से संबंधित डिफ़ॉल्ट नामस्थान नोड को आपके XPath अभिव्यक्ति के मूल्यांकन के परिणामस्वरूप नष्ट नहीं किया जा सकता है - इस प्रकार some_prefix:a को पाठ के क्रमबद्ध होने पर यह नामस्थान नोड दिखाया जाता है।

समाधान: अवांछित नामस्थान नोड को हटाने के लिए XPath होस्ट करने वाले अपने पसंदीदा पीएल का उपयोग करें।

उदाहरण के लिए , अगर होस्टिंग भाषा XSLT है:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:d="default_ns"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="/"> 
    <xsl:apply-templates mode="delNS" 
    select="/*/d:subelement/*[1]"/> 
</xsl:template> 

<xsl:template match="*" mode="delNS"> 
    <xsl:element name="{name()}" namespace="{namespace-uri()}"> 
    <xsl:copy-of select="namespace::*[name()]"/> 
    <xsl:copy-of select="@*"/> 
    <xsl:apply-templates mode="delNS" select="node()"/> 
    </xsl:element> 
</xsl:template> 
</xsl:stylesheet> 

जब इस बदलाव प्रदान की XML दस्तावेज़ पर लागू किया जाता है:

<root xmlns="default_ns"> 
    <subelement> 
     <!-- here we can have an element of any namespace --> 
     <some_prefix:a xmlns:some_prefix="some_namespace"> 
      <some_prefix:b/> 
     </some_prefix:a> 
    </subelement> 
</root> 

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

<some_prefix:a xmlns:some_prefix="some_namespace"> 
    <some_prefix:b/> 
</some_prefix:a> 
+0

धन्यवाद Dimitre:

यह मेरा अंतिम समाधान अजगर का उपयोग कर रहा है! वास्तव में मैं lxml का उपयोग कर परिणाम प्राप्त करना चाहता हूँ। आपके anwser के बाद मुझे [इसी तरह की समस्या] मिली (http://stackoverflow.com/questions/6365422/python-lxml-adds-unused-namespaces) और [इस anwser] में पहली टिप्पणी (http://stackoverflow.com/ ए/6365981/629762) सुझाव देते हैं कि गहरी कॉपी और क्लीन_नामस्थान का उपयोग करके इसे कैसे करें: 'child = deepcopy (child) etree.cleanup_namespaces (child)' – Marcin

+0

@Marcin क्या वे दो अलग-अलग आदेश हैं? इसके अलावा, मेरे दुभाषिया का कहना है कि "गहरी कॉपी" परिभाषित नहीं है "। – NoBugs

+0

@NoBugs ये दो अलग-अलग आदेश हैं। इसके अलावा, मैंने पाया कि 'etree.cleanup_namespaces' की आवश्यकता नहीं है। अवांछित नेमस्पेस को हटाने के लिए केवल 'deepcopy' का उपयोग करें। 'deepcopy' फ़ंक्शन [कॉपी] (http://docs.python.org/library/copy.html) मॉड्यूल से आता है। यह अंतिम कोड है: बच्चे = मूल्यांकनकर्ता। मूल्यांकन ('// def: subelement/child :: *') [0] बच्चे = गहरी प्रतिद्वंद्वी (बच्चे) a_string = etree.tostring (बच्चा) – Marcin