Python 3 XML Дублировать и переименовать элемент, если другой элемент не найден - PullRequest
1 голос
/ 14 апреля 2020

У меня есть файл IN. xml, который нужно исправить, что вызвало у меня головную боль:)

Проблема, которую нужно решить, - это посмотреть в файле IN. xml, если хотя бы один "Classe_Temporelle_Distributeur" существует в Элемент «Donnees_Releve».

Если нет, скопируйте элемент «Classe_Temporelle» (который всегда существует) и переименуйте его в «Classe_Temporelle_Distributeur».

Пример ниже с IN. xml и ожидаемым OUT. xml файлом

Так выглядит файл IN. xml

<filename>
 <prm>
  <Donnees_Releve>
   <Classe_Temporelle>
    <data></data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data></data>
   </Classe_Temporelle>
  </Donnees_Releve>
 <Donnees_Releve>
   <Classe_Temporelle>
    <data></data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data></data>
   </Classe_Temporelle>
  </Donnees_Releve> 
 </prm>
<filename>

Это ожидаемый файл OUT. xml file

Примечание. Элементы "Classe_Temporelle_Distributeur" добавляются, если они не представлены в узле "Donnees_Releve", это копия узла Classe_Temporelle.

Каждый элемент может иметь 1-n подэлемента. Каждый Classe_Temporelle должен иметь соответствующий Classe_Temporelle_Distributeur, (каждый Classe_Temporelle не содержит одинаковые данные.)

<filename>
     <prm>
      <Donnees_Releve>
       <Classe_Temporelle>
        <data></data>
       </Classe_Temporelle>
       <Classe_Temporelle>
        <data></data>
       </Classe_Temporelle>
       <Classe_Temporelle_Distributeur>
        <data></data>
       </Classe_Temporelle_Distributeur>
       <Classe_Temporelle_Distributeur>
        <data></data>
       </Classe_Temporelle_Distributeur>
      </Donnees_Releve>
      <Donnees_Releve>
       <Classe_Temporelle>
        <data></data>
       </Classe_Temporelle>
       <Classe_Temporelle>
        <data></data>
       </Classe_Temporelle>
       <Classe_Temporelle_Distributeur>
        <data></data>
       </Classe_Temporelle_Distributeur>
       <Classe_Temporelle_Distributeur>
        <data></data>
       </Classe_Temporelle_Distributeur>
      </Donnees_Releve> 
     </prm>
    <filename>

Код, который я написал

Работают частично, но это только исправляет первый элемент "Classe_Temporelle" каждого Donnees_Releve. Но он может иметь много подэлементов, тогда он не соответствует запросу

import xml.etree.ElementTree as ET


file = 'IN/IN.xml'

tree = ET.parse(file)
root = tree.getroot()

#loop on each PRM
for prm in root.iter('PRM'):


    # Loop on each Donnees_Releve

    for classeDistributeur in prm.iter('Donnees_Releve'):

        Classe_Temporelle_Distributeur = classeDistributeur.find('Classe_Temporelle_Distributeur')

        if Classe_Temporelle_Distributeur is None:
            print("Classe_Temporelle_Distributeur not found")

            # copy element Classe_Temporelle in Classe_Temporelle_Distributeur

            Classe_Temporelle = classeDistributeur.find('Classe_Temporelle')

            dupe = copy.deepcopy(Classe_Temporelle) #copy node
            classeDistributeur.append(dupe) #insert the new node

            # Rename Node
            Classe_Temporelle.tag = "Classe_Temporelle_Distributeur"


        else :
            print("Ok nothing to do")


tree.write('OUT/out.xml')

Не могли бы вы мне помочь?

Ответы [ 2 ]

0 голосов
/ 15 апреля 2020

Проблема с вашим кодом заключается в том, что вы вызываете find , который находит только first вхождение элемента с заданным именем. Вместо этого вы должны использовать findall и al oop.

Другое (необязательное) исправление - использовать более короткие имена.

Поэтому измените свой код, например:

for dr in root.iter('Donnees_Releve'):
    if dr.find('Classe_Temporelle_Distributeur') is None:
        for ct in dr.findall('Classe_Temporelle'):
            wrk = copy.deepcopy(ct)
            wrk.tag = 'Classe_Temporelle_Distributeur'
            dr.append(wrk)

Боюсь, что другое решение скопирует существующие Classe_Temporelle элементы в Classe_Temporelle_Distributeur независимо от того, существует ли этот элемент (в этом случае не следует делать копию).

0 голосов
/ 15 апреля 2020

Рассмотрим XSLT , язык специального назначения, предназначенный для преобразования XML файлов и избежания каких-либо процедурных XML отображений на уровне общего назначения в данном случае Python. Хотя встроенный модуль Python, etree, не поддерживает XSLT, это сторонний модуль, lxml поддерживает XSLT 1.0 и полный XPath 1.0.

В качестве альтернативы, Python вызовите любой внешний XSLT 1.0 - 3.0 процессор , такой как Saxon или Xalan, или даже используйте любой другой язык общего назначения для запуска преобразования XSLT (т. Е. Java, Javascript, C#, C ++, PHP, Perl, R, VB), поскольку каждый из них несет свои собственные библиотеки XSLT.

Расширение вашего примера для представления первых трех Python и XSLT Пользователи золотых значков StackOverflow, XSLT могут легко дублировать необходимые узлы, используя несколько шаблонных режимов.

XSLT (сохранить как файл .xsl, специальный. xml файл)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" encoding="UTF-8"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Donnees_Releve">
    <xsl:copy>
      <xsl:apply-templates select="Classe_Temporelle" mode="t1"/>
      <xsl:apply-templates select="Classe_Temporelle" mode="t2"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Classe_Temporelle" mode="t1">
    <xsl:copy>
      <xsl:apply-templates select="data" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Classe_Temporelle" mode="t2">
    <Classe_Temporelle_Distributeur>
      <xsl:apply-templates select="data" />
    </Classe_Temporelle_Distributeur>
  </xsl:template>

</xsl:stylesheet>

Ввод XML

<?xml version="1.0" encoding="utf-8" ?>
<filename>
 <prm>
  <Donnees_Releve>
   <Classe_Temporelle>
    <data>Martijn Pietersr</data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data>Alex Martelli</data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data>unutbu</data>
   </Classe_Temporelle>
  </Donnees_Releve>
 <Donnees_Releve>
   <Classe_Temporelle>
    <data>Dimitre Novatchev</data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data>Martin Honnen</data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data>Michael Kay</data>
   </Classe_Temporelle>
  </Donnees_Releve> 
 </prm>
</filename>

Python (нет for l oop или if logi c)

import lxml.etree as et

# INPUT XML AND XSL SOURCES
xml = et.parse('Input.xml')
xsl = et.parse('Script.xsl')

# RUN TRANSFORMATION
transformer = et.XSLT(xsl)
new_xml = transformer(xml)

# PRINT TO CONSOLE
print(new_xml)

# SAVE TO FILE
with open('Output.xml', 'wb') as f:
   f.write(new_xml)

Выход XML

<?xml version="1.0" encoding="utf-16"?>
<filename>
  <prm>
    <Donnees_Releve>
      <Classe_Temporelle>
        <data>Martijn Pietersr</data>
      </Classe_Temporelle>
      <Classe_Temporelle>
        <data>Alex Martelli</data>
      </Classe_Temporelle>
      <Classe_Temporelle>
        <data>unutbu</data>
      </Classe_Temporelle>
      <Classe_Temporelle_Distributeur>
        <data>Martijn Pietersr</data>
      </Classe_Temporelle_Distributeur>
      <Classe_Temporelle_Distributeur>
        <data>Alex Martelli</data>
      </Classe_Temporelle_Distributeur>
      <Classe_Temporelle_Distributeur>
        <data>unutbu</data>
      </Classe_Temporelle_Distributeur>
    </Donnees_Releve>
    <Donnees_Releve>
      <Classe_Temporelle>
        <data>Dimitre Novatchev</data>
      </Classe_Temporelle>
      <Classe_Temporelle>
        <data>Martin Honnen</data>
      </Classe_Temporelle>
      <Classe_Temporelle>
        <data>Michael Kay</data>
      </Classe_Temporelle>
      <Classe_Temporelle_Distributeur>
        <data>Dimitre Novatchev</data>
      </Classe_Temporelle_Distributeur>
      <Classe_Temporelle_Distributeur>
        <data>Martin Honnen</data>
      </Classe_Temporelle_Distributeur>
      <Classe_Temporelle_Distributeur>
        <data>Michael Kay</data>
      </Classe_Temporelle_Distributeur>
    </Donnees_Releve>
  </prm>
</filename>

Демоверсия

...