将命名空间放入 Python 中的不同 XML 标签
Putting Namespaces into Different XML Tags in Python
我在 tmp/Program.ev3p
中有一个 xml 文件:
<?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 中实现?
目前,未记录的 ElementTree._namespace_map[uri] = prefix
是较旧的 Python 版本 (< 1.3),用于将命名空间分配给更新的、记录在案的 ElementTree.register_namespace(prefix, uri)
。但即使是这种方法也不能解决根本问题,文档强调此分配适用于全局并替换任何以前的命名空间或前缀:
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.
为了达到您想要的结果,并且由于您的 XML 有点复杂,具有多个默认和 non-default 名称空间,请考虑 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(例如 Saxon、Xalan)。
具体来说,您可以使用 doc 之类的临时前缀来映射最低级别父级 VirtualInstrument 的默认命名空间,并使用此前缀以确定所需的节点。使用 identity transform 模板复制所有其他元素。此外,因为您要将元素添加到默认命名空间,所以您可以使用 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)
我在 tmp/Program.ev3p
中有一个 xml 文件:
<?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 中实现?
目前,未记录的 ElementTree._namespace_map[uri] = prefix
是较旧的 Python 版本 (< 1.3),用于将命名空间分配给更新的、记录在案的 ElementTree.register_namespace(prefix, uri)
。但即使是这种方法也不能解决根本问题,文档强调此分配适用于全局并替换任何以前的命名空间或前缀:
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.
为了达到您想要的结果,并且由于您的 XML 有点复杂,具有多个默认和 non-default 名称空间,请考虑 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(例如 Saxon、Xalan)。
具体来说,您可以使用 doc 之类的临时前缀来映射最低级别父级 VirtualInstrument 的默认命名空间,并使用此前缀以确定所需的节点。使用 identity transform 模板复制所有其他元素。此外,因为您要将元素添加到默认命名空间,所以您可以使用 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)