Я разбираю XML-файл, созданный внешним program. Затем я хотел бы добавить пользовательские аннотации к этому файлу, используя собственное пространство имен. Мой вход выглядит, как показано ниже: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>
Является ли это можно заставить lxml написать это объявление только один раз в родительском элементе, например sbml
или listOfSpecies
? Или есть веская причина не делать этого? В результате я хочу бы:
<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>
важная проблема состоит в том, что существующие данные, которые считываются из файла должны быть сохранены, так что я не могу просто сделать новый корневой элемент (я думаю?).
EDIT: код прилагается ниже.
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
Показать код. – Marcin
@ Марцин: сделано. Какие-нибудь советы? – kai
@mzjin Мой вход содержит все, кроме тегов ' '. Цель состоит в том, чтобы вставить эти теги (или подобные, например, «kjw: score» или «kjw: length») каждому виду в этом списке. Имеет ли это смысл, или я должен опубликовать весь файл (предположил, что мой первоначальный вопрос был достаточно длинным, как есть)? –
kai