Изменить пространства имен в данном документе XML с помощью lxml
У меня есть XML-документ, который выглядит так:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://someurl/Oldschema"
xsi:schemaLocation="http://someurl/Oldschema Oldschema.xsd"
xmlns:framework="http://someurl/Oldframework">
<framework:tag1> ... </framework:tag1>
<framework:tag2> <tagA> ... </tagA> </framwork:tag2>
</root>
Все, что я хочу сделать, это изменить http://someurl/Oldschema
в http://someurl/Newschema
а также http://someurl/Oldframework
в http://someurl/Newframework
и оставьте оставшийся документ без изменений. С некоторыми соображениями из этой темы lxml: добавить пространство имен во входной файл, я попробовал следующее:
def fix_nsmap(nsmap, tag):
"""update the old nsmap-dict with the new schema-urls. Example:
fix_nsmap({"framework": "http://someurl/Oldframework",
None: "http://someurl/Oldschema"}) ==
{"framework": "http://someurl/Newframework",
None: "http://someurl/Newschema"}"""
...
from lxml import etree
root = etree.parse(XMLFILE).getroot()
root_tag = root.tag.split("}")[1]
nsmap = fix_nsmap(root.nsmap)
new_root = etree.Element(root_tag, nsmap=nsmap)
new_root[:] = root[:]
# ... fix xsi:schemaLocation
return etree.tostring(new_root, pretty_print=True, encoding="UTF-8",
xml_declaration=True)
Это производит правильные "атрибуты" в корневом теге, но полностью терпит неудачу для остальной части документа:
<network xmlns:framework="http://someurl/Newframework"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://someurl/Newschema"
xsi:schemaLocation="http://someurl/Newschema Schema.xsd">
<ns0:tag1 xmlns:ns0="http://someurl/Oldframework"> ... </ns0:information>
<ns1:tag2 xmlns:ns1="http://someurl/Oldframework"
xmlns:ns2="http://someurl/Oldschema">
<ns2:tagA> ... </ns2:tagA>
</ns1:tag2>
Что не так с моим подходом? Есть ли другой способ изменить пространства имен? Может быть, я мог бы использовать xslt?
Спасибо!
Денис
1 ответ
Все, что я хочу сделать, это изменить
http://someurl/Oldschema
вhttp://someurl/Newschema
а такжеhttp://someurl/Oldframework
вhttp://someurl/Newframework
и оставьте оставшийся документ без изменений.
Я бы сделал простую текстовую операцию поиска и замены. Это гораздо проще, чем возиться с узлами XML. Как это:
with open("input.xml", "r") as infile, open("output.xml", "w") as outfile:
data = infile.read()
data = data.replace("http://someurl/Oldschema", "http://someurl/Newschema")
data = data.replace("http://someurl/Oldframework", "http://someurl/Newframework")
outfile.write(data)
Другой вопрос, который вас вдохновил, - это добавление нового пространства имен (и сохранение старых). Но вы пытаетесь изменить существующие объявления пространства имен. Создание нового корневого элемента и копирование дочерних узлов в этом случае не работает.
Эта строка:
new_root[:] = root[:]
превращает дочерние элементы исходного корневого элемента в дочерние элементы нового корневого элемента. Но эти дочерние узлы все еще связаны со старыми пространствами имен. Таким образом, они должны быть изменены / воссозданы тоже. Я думаю, что возможно было бы найти разумный способ сделать это, но я не думаю, что вам это нужно. Текстовый поиск и замена достаточно хороши, ИМХО.