Помещение пространств имен в разные теги XML в Python - PullRequest
1 голос
/ 24 мая 2019

У меня есть XML-файл в tmp/Program.ev3p:

<?xml version="1.0" encoding="utf-8"?>
<SourceFile Version="1.0.2.10" xmlns="http://www.ni.com/SourceModel.xsd">
    <Namespace Name="Project">
        <VirtualInstrument IsTopLevel="false" IsReentrant="false" Version="1.0.2.0" OverridingModelDefinitionType="X3VIDocument" xmlns="http://www.ni.com/VirtualInstrument.xsd">
            <FrontPanel>
                <fpruntime:FrontPanelCanvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:fpruntime="clr-namespace:NationalInstruments.LabVIEW.FrontPanelRuntime;assembly=NationalInstruments.LabVIEW.FrontPanelRuntime" xmlns:Model="clr-namespace:NationalInstruments.SourceModel.Designer;assembly=NationalInstruments.SourceModel" x:Name="FrontPanel" Model:DesignerSurfaceProperties.CanSnapToObjects="True" Model:DesignerSurfaceProperties.SnapToObjects="True" Model:DesignerSurfaceProperties.ShowSnaplines="True" Model:DesignerSurfaceProperties.ShowControlAdorners="True" Width="640" Height="480" />
            </FrontPanel>
            <BlockDiagram Name="__RootDiagram__">
                <StartBlock Id="n1" Bounds="0 0 70 91" Target="X3\.Lib:StartBlockTest">
                    <ConfigurableMethodTerminal>
                        <Terminal Id="Result" Direction="Output" DataType="Boolean" Hotspot="0.5 1" Bounds="0 0 0 0" />
                    </ConfigurableMethodTerminal>
                    <Terminal Id="SequenceOut" Direction="Output" DataType="NationalInstruments:SourceModel:DataTypes:X3SequenceWireDataType" Hotspot="1 0.5" Bounds="52 33 18 18" />
                </StartBlock>
            </BlockDiagram>
        </VirtualInstrument>
    </Namespace>
</SourceFile>

Я пытаюсь изменить его следующим кодом:

import xml.etree.ElementTree as ET

tree = ET.parse('tmp/Program.ev3p')
root = tree.getroot()

namespaces = {'http://www.ni.com/SourceModel.xsd': '' ,
              'http://www.ni.com/VirtualInstrument.xsd':'',
              'http://schemas.microsoft.com/winfx/2006/xaml/presentation':'',
              'http://schemas.microsoft.com/winfx/2006/xaml':'x',
              'clr-namespace:NationalInstruments.LabVIEW.FrontPanelRuntime;assembly=NationalInstruments.LabVIEW.FrontPanelRuntime':'fpruntime',
              'clr-namespace:NationalInstruments.SourceModel.Designer;assembly=NationalInstruments.SourceModel': 'Model',
              }

for uri, prefix in namespaces.items():
    ET._namespace_map[uri] = prefix

diagram = root[0][0][1]
elem = ET.Element('Data')
diagram.append(elem)

tree.write('tmp/Program.ev3p',"UTF-8",xml_declaration=True)

После запуска кода мой xml-файл содержит:

<?xml version='1.0' encoding='UTF-8'?>
<SourceFile xmlns="http://www.ni.com/SourceModel.xsd" xmlns="http://www.ni.com/VirtualInstrument.xsd" xmlns:Model="clr-namespace:NationalInstruments.SourceModel.Designer;assembly=NationalInstruments.SourceModel" xmlns:fpruntime="clr-namespace:NationalInstruments.LabVIEW.FrontPanelRuntime;assembly=NationalInstruments.LabVIEW.FrontPanelRuntime" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Version="1.0.2.10">
    <Namespace Name="Project">
        <VirtualInstrument IsReentrant="false" IsTopLevel="false" OverridingModelDefinitionType="X3VIDocument" Version="1.0.2.0">
            <FrontPanel>
                <fpruntime:FrontPanelCanvas Height="480" Width="640" Model:DesignerSurfaceProperties.CanSnapToObjects="True" Model:DesignerSurfaceProperties.ShowControlAdorners="True" Model:DesignerSurfaceProperties.ShowSnaplines="True" Model:DesignerSurfaceProperties.SnapToObjects="True" x:Name="FrontPanel" />
            </FrontPanel>
            <BlockDiagram Name="__RootDiagram__">
                <StartBlock Bounds="0 0 70 91" Id="n1" Target="X3\.Lib:StartBlockTest">
                    <ConfigurableMethodTerminal>
                        <Terminal Bounds="0 0 0 0" DataType="Boolean" Direction="Output" Hotspot="0.5 1" Id="Result" />
                    </ConfigurableMethodTerminal>
                    <Terminal Bounds="52 33 18 18" DataType="NationalInstruments:SourceModel:DataTypes:X3SequenceWireDataType" Direction="Output" Hotspot="1 0.5" Id="SequenceOut" />
                </StartBlock>
            <Data /></BlockDiagram>
        </VirtualInstrument>
    </Namespace>
</SourceFile>

Мне нужно, чтобы пространства имен были в тегах, которые они были зарегистрированы в исходном файле, вместо того, чтобы все они были внутри SourceFile, возможно ли достичь этого в python?

1 Ответ

1 голос
/ 24 мая 2019

В настоящее время недокументированное ElementTree._namespace_map[uri] = prefix является более старой версией Python (<1.3) для присвоения пространства имен более актуальной, документированной <a href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.register_namespace" rel="nofollow noreferrer">ElementTree.register_namespace(prefix, uri).Но даже этот метод не решает проблему с корнем, и в документах подчеркивается, что это назначение применяется глобально и заменяет любое предыдущее пространство имен или префикс:

xml.etree.ElementTree.register_namespace (prefix, uri) Регистрирует префикс пространства имен.Реестр является глобальным, и любое существующее сопоставление для данного префикса или URI пространства имен будет удалено. prefix - это префикс пространства имен. uri - это пространство имен uri.Теги и атрибуты в этом пространстве имен будут сериализованы с заданным префиксом, если это вообще возможно.


Для достижения желаемого результата и потому, что ваш XML немного сложен с несколькими значениями по умолчанию и непространства имен по умолчанию, рассмотрим XSLT , язык специального назначения для преобразования файлов XML.Python может запускать сценарии XSLT 1.0 со сторонним модулем lxml (не встроенным etree).Кроме того, XSLT является переносимым, поэтому сам код может выполняться на других языках (Java, C #, PHP, VB) и выделенных процессорах (например, Saxon, Xalan).

В частности, вы можете использоватьвременный префикс, например doc , для сопоставления пространства имен по умолчанию для родительского элемента нижнего уровня, VirtualInstrument и использования этого префикса для определения необходимых узлов.Все остальные элементы копируются как есть с шаблоном тождественного преобразования .Кроме того, поскольку вы добавляете элемент в пространство имен по умолчанию, вы можете назначить его с помощью тега xsl:element.

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

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:doc="http://www.ni.com/VirtualInstrument.xsd">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="doc:BlockDiagram">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <xsl:element name="Data" namespace="http://www.ni.com/VirtualInstrument.xsd"/>      
    </xsl:copy>
  </xsl:template>    

</xsl:stylesheet>

Python

import lxml.etree as ET

# LOAD XML AND XSL 
dom = ET.parse('Input.xml')
xslt = ET.parse('XSLTScript.xsl')

# TRANSFORM INPUT
transform = ET.XSLT(xslt)
newdom = transform(dom)

# OUTPUT RESULT TREE TO CONSOLE
print(newdom) 

# SAVE RESULT TREE AS XML
with open('Output.xml','wb') as f:
     f.write(newdom)

XSLT Demo

...