2012-07-05 15 views
12

इनपुट नाम में नामस्थान जोड़ें मैं बाहरी program द्वारा उत्पन्न एक XML फ़ाइल को पार्स कर रहा हूं। मैं अपने नामस्थान का उपयोग करके, इस फ़ाइल में कस्टम एनोटेशन जोड़ना चाहूंगा। मेरे इनपुट लग रहा है नीचे के रूप में:lxml: फ़ाइल

<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4"> 
    <model metaid="untitled" id="untitled"> 
    <annotation>...</annotation> 
    <listOfUnitDefinitions>...</listOfUnitDefinitions> 
    <listOfCompartments>...</listOfCompartments> 
    <listOfSpecies> 
     <species metaid="s1" id="s1" name="GenA" compartment="default" initialAmount="0"> 
     <annotation> 
      <celldesigner:extension>...</celldesigner:extension> 
     </annotation> 
     </species> 
     <species metaid="s2" id="s2" name="s2" compartment="default" initialAmount="0"> 
     <annotation> 
      <celldesigner:extension>...</celldesigner:extension> 
     </annotation> 
     </species> 
    </listOfSpecies> 
    <listOfReactions>...</listOfReactions> 
    </model> 
</sbml> 

मुद्दा जा रहा है कि lxml केवल नामस्थान वाणी जब वे उपयोग किया जाता है, जिसका अर्थ है घोषणा को कई बार दोहराया जाता है, इसलिए (सरलीकृत) की तरह:

<sbml xmlns="namespace" xmlns:celldesigner="morenamespace" level="2" version="4"> 
    <listOfSpecies> 
    <species> 
     <kjw:test xmlns:kjw="http://this.is.some/custom_namespace"/> 
     <celldesigner:data>Some important data which must be kept</celldesigner:data> 
    </species> 
    <species> 
     <kjw:test xmlns:kjw="http://this.is.some/custom_namespace"/> 
    </species> 
    .... 
    </listOfSpecies> 
</sbml> 

यह है 0xया listOfSpecies जैसे माता-पिता तत्व में केवल एक बार इस घोषणा को लिखने के लिए lxml को मजबूर करना संभव है? या ऐसा करने का कोई अच्छा कारण नहीं है? परिणाम मैं चाहता हूँ होगा:

<sbml xmlns="namespace" xmlns:celldesigner="morenamespace" level="2" version="4" xmlns:kjw="http://this.is.some/custom_namespace"> 
    <listOfSpecies> 
    <species> 
     <kjw:test/> 
     <celldesigner:data>Some important data which must be kept</celldesigner:data> 
    </species> 
    <species> 
     <kjw:test/> 
    </species> 
    .... 
    </listOfSpecies> 
</sbml> 

महत्वपूर्ण समस्या यह है कि जो एक फ़ाइल से पढ़ा जाता है मौजूदा डेटा रखा जाना चाहिए है, तो मैं बस (मुझे लगता है कि?) एक नया मूल तत्व नहीं कर सकता।

संपादित करें: नीचे कोड कोड।

def annotateSbml(sbml_input): 
    from lxml import etree 

    checkSbml(sbml_input) # Makes sure the input is valid sbml/xml. 

    ns = "http://this.is.some/custom_namespace" 
    etree.register_namespace('kjw', ns) 

    sbml_doc = etree.ElementTree() 
    root = sbml_doc.parse(sbml_input, etree.XMLParser(remove_blank_text=True)) 
    nsmap = root.nsmap 
    nsmap['sbml'] = nsmap[None] # Makes code more readable, but seems ugly. Any alternatives to this? 
    nsmap['kjw'] = ns 
    ns = '{' + ns + '}' 
    sbmlns = '{' + nsmap['sbml'] + '}' 

    for species in root.findall('sbml:model/sbml:listOfSpecies/sbml:species', nsmap): 
    species.append(etree.Element(ns + 'test')) 

    sbml_doc.write("test.sbml.xml", pretty_print=True, xml_declaration=True) 

    return 
+1

अपने कोड दिखाएं। – Marcin

+0

@ मार्सिन: किया गया। कोई सुझाव? – kai

+0

@mzjin मेरे इनपुट में ' 'टैग को छोड़कर सबकुछ शामिल है। इसका उद्देश्य इस सूची में प्रत्येक प्रजाति के लिए ऐसे टैग (या समान, उदा। 'Kjw: score' या 'kjw: length') डालना है। क्या यह समझ में आता है, या मुझे पूरी फाइल पोस्ट करनी चाहिए (मुझे लगता है कि मेरा मूल प्रश्न काफी लंबा था)? – kai

उत्तर

8

एलएक्सएमएल में नोड के नामस्थान मैपिंग को संशोधित करना संभव नहीं है। this open ticket देखें जिसमें यह सुविधा एक विशलिस्ट सूची के रूप में है।

यह lxml मेलिंग सूची है, जहां एक workaround replacing the root node एक विकल्प के रूप में दिया जाता है पर this thread से जन्म लिया है। यद्यपि रूट नोड को बदलने के साथ कुछ समस्याएं हैं: ऊपर दिए गए टिकट को देखें।

मैं सुझाव जड़ प्रतिस्थापन वैकल्पिक हल कोड संपूर्णता के लिए यहाँ डाल देता हूँ: कच्चे एक्सएमएल के साथ सीधे निपटने के बजाय

>>> DOC = """<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4"> 
... <model metaid="untitled" id="untitled"> 
...  <annotation>...</annotation> 
...  <listOfUnitDefinitions>...</listOfUnitDefinitions> 
...  <listOfCompartments>...</listOfCompartments> 
...  <listOfSpecies> 
...  <species metaid="s1" id="s1" name="GenA" compartment="default" initialAmount="0"> 
...   <annotation> 
...   <celldesigner:extension>...</celldesigner:extension> 
...   </annotation> 
...  </species> 
...  <species metaid="s2" id="s2" name="s2" compartment="default" initialAmount="0"> 
...   <annotation> 
...   <celldesigner:extension>...</celldesigner:extension> 
...   </annotation> 
...  </species> 
...  </listOfSpecies> 
...  <listOfReactions>...</listOfReactions> 
... </model> 
... </sbml>""" 
>>> 
>>> from lxml import etree 
>>> from StringIO import StringIO 
>>> NS = "http://this.is.some/custom_namespace" 
>>> tree = etree.ElementTree(element=None, file=StringIO(DOC)) 
>>> root = tree.getroot() 
>>> nsmap = root.nsmap 
>>> nsmap['kjw'] = NS 
>>> new_root = etree.Element(root.tag, nsmap=nsmap) 
>>> new_root[:] = root[:] 
>>> new_root.append(etree.Element('{%s}%s' % (NS, 'test'))) 
>>> new_root.append(etree.Element('{%s}%s' % (NS, 'test'))) 

>>> print etree.tostring(new_root, pretty_print=True) 
<sbml xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" xmlns:kjw="http://this.is.some/custom_namespace" xmlns="http://www.sbml.org/sbml/level2/version4"><model metaid="untitled" id="untitled"> 
    <annotation>...</annotation> 
    <listOfUnitDefinitions>...</listOfUnitDefinitions> 
    <listOfCompartments>...</listOfCompartments> 
    <listOfSpecies> 
     <species metaid="s1" id="s1" name="GenA" compartment="default" initialAmount="0"> 
     <annotation> 
      <celldesigner:extension>...</celldesigner:extension> 
     </annotation> 
     </species> 
     <species metaid="s2" id="s2" name="s2" compartment="default" initialAmount="0"> 
     <annotation> 
      <celldesigner:extension>...</celldesigner:extension> 
     </annotation> 
     </species> 
    </listOfSpecies> 
    <listOfReactions>...</listOfReactions> 
    </model> 
<kjw:test/><kjw:test/></sbml> 
+1

भविष्य के संदर्भ के लिए इसे एक छोटे बदलाव (कम से कम पाइथन 3.2 पर) की आवश्यकता होती है, अन्यथा '** root.nsmap' से टाइप एरर देता है जब यह 'कोई नहीं' 'नामस्थान' के रूप में 'कोई नहीं' के रूप में एक स्ट्रिंग नहीं होता है। 'Nsmap = root.nsmap;' 'nsmap ['kjw'] = NS;' 'new_root = etree.Element (root.tag, nsmap = nsmap); 'काम करता है। – kai

+0

अच्छी पकड़, – jterrace

+0

अपडेट किया गया आपको भी attrib, text, और (संभावना नहीं है, लेकिन केवल पूर्णता के लिए) की प्रतिलिपि बनाने की आवश्यकता है। 'nsmap = dict (kjw = NS, nsmap = nsmap)) 'गलत है; यह सिर्फ 'nsmap = nsmap' होना चाहिए – jfs

0

आप रूट तत्व को अपने nsmap में 'kjw' जोड़ने के लिए प्रतिस्थापित कर सकते हैं। फिर xmlns घोषणा रूट तत्व में ही होगी।

3

तुम भी के लिए भाषा का बाइंडिंग के साथ SBML दस्तावेजों से छेड़छाड़ के लिए एक पुस्तकालय, LibSBML की ओर दिखाई दे सकता है , दूसरों के बीच, अजगर। वहाँ आप इसे इस तरह का प्रयोग करेंगे:

 
>>> from libsbml import * 
>>> doc = readSBML('Dropbox/SBML Models/BorisEJB.xml') 
>>> species = doc.getModel().getSpecies('MAPK') 
>>> species.appendAnnotation('<kjw:test xmlns:kjw="http://this.is.some/custom_namespace"/>') 
0 
>>> species.toSBML() 
'<species id="MAPK" compartment="compartment" initialConcentration="280" boundaryCondition="false">\n <annotation>\n 
<kjw:test xmlns:kjw="http://this.is.some/custom_namespace"/>\n </annotation>\n</species>' 
>>> 

1

आप अस्थायी रूप से रूट नोड, कि काम कर देता है के लिए एक namespaced विशेषता जोड़ें।

ns = '{http://this.is.some/custom_namespace}' 

# add 'kjw:foobar' attribute to root node 
root.set(ns+'foobar', 'foobar') 

# add kjw namespace elements (or attributes) elsewhere 
... get child element species ... 
species.append(etree.Element(ns + 'test')) 

# remove temporary namespaced attribute from root node 
del root.attrib[ns+'foobar'] 
1

मैं जानता हूँ कि इस पुराने सवाल है, लेकिन यह अभी भी मान्य और lxml 3.5.0 के रूप में, वहाँ शायद इस समस्या का बेहतर समाधान है:

cleanup_namespaces() एक नया तर्क top_nsmap कि परिभाषाओं चालें स्वीकार करता है पेड़ के शीर्ष पर उपलब्ध उपसर्ग-नामस्थान मैपिंग का।

तो अब नाम स्थान नक्शा इस के लिए सरल कॉल के साथ ले जाया जा सकता:

nsmap = {'kjw': 'http://this.is.some/custom_namespace'} 
etree.cleanup_namespaces(root, top_nsmap=nsmap) 
संबंधित मुद्दे