简体   繁体   中英

Putting Namespaces into Different XML Tags in Python

I have an xml file in 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>

I am trying to modify it with the following code:

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)

After running the code, my xml file contains:

<?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>

I need the namespaces to be in the tags they were registered in the original file instead of having all of them inside SourceFile , is it possible to achieve so in python?

Currently, the undocumented ElementTree._namespace_map[uri] = prefix is the older Python version (< 1.3) for namespace assignment to the more current, documented ElementTree.register_namespace(prefix, uri) . But even this method does not resolve the root issue and docs emphasize this assignment applies globally and replaces any previous namespace or prefix:

xml.etree.ElementTree.register_namespace(prefix, uri)
Registers a namespace prefix. The registry is global, and any existing mapping for either the given prefix or the namespace URI will be removed. prefix is a namespace prefix. uri is a namespace uri. Tags and attributes in this namespace will be serialized with the given prefix, if at all possible.


To achieve your desired result and because your XML is a bit complex with multiple default and non-default namespaces, consider XSLT , the special-purpose language to transform XML files. Python can run XSLT 1.0 scripts with the third-party module, lxml (not built-in etree ). Additionally, XSLT is portable so very code can run in other languages (Java, C#, PHP, VB) and dedicated processors (eg, Saxon, Xalan).

Specifically, you can use a temporary prefix like doc to map the default namespace of lowest level parent, VirtualInstrument and use this prefix to identify the needed nodes. All other elements are copied over as is with the identity transform template. Also, because you are adding an element to the default namespace you can assign it with the xsl:element tag.

XSLT (save below as .xsl file, a special .xml file)

<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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM