我有 2 个 XML 文件要合并,但我不想更改原始文件中的任何现有元素。在 linux 系统上执行此操作的最佳方法是什么?
注意:有一些关于使用 XSLT 的帖子似乎接近我需要的,但我没有安装 XSLT 处理器(我也没有安装它的权限)。也就是说,我确实安装了xsltproc
,但我不确定这是否有帮助。如果xsltproc
有帮助,请提供一个合适的命令行示例。
以下是原始文件的片段:
<?xml version="1.0" encoding="utf-8"?>
<config xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
<Comment>This file was automatically generated.</Comment>
<FieldAttrs>
<Name>FieldAttrsAll</Name>
<Field>
<Name>wLegExchInstIds</Name>
<Fid>6203</Fid>
<Type>StringVector</Type>
<CheckModified>true</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>false</ClearDaily>
</Field>
<Field>
<Name>wPartitionId</Name>
<Fid>5886</Fid>
<Type>Integer</Type>
<CheckModified>true</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>false</ClearDaily>
</Field>
</FieldAttrs>
</config>
这是我需要合并的新文件:
<?xml version="1.0" encoding="utf-8"?>
<config xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
<Comment>This file was automatically generated.</Comment>
<FieldAttrs>
<Name>FieldAttrsAll</Name>
<Field>
<Name>wLegExchInstIds</Name>
<Fid>6203</Fid>
<Type>StringVector</Type>
<CheckModified>false</CheckModified>
<PublishField>false</PublishField>
<ClearDaily>false</ClearDaily>
</Field>
<Field>
<Name>wPartitionId</Name>
<Fid>5886</Fid>
<Type>Integer</Type>
<CheckModified>false</CheckModified>
<PublishField>false</PublishField>
<ClearDaily>false</ClearDaily>
</Field>
<Field>
<Name>wUnverifiedPriceIndicator</Name>
<Fid>5885</Fid>
<Type>Bool</Type>
<CheckModified>true</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>true</ClearDaily>
</Field>
<Field>
<Name>wCorrIsIrregular</Name>
<Fid>5884</Fid>
<Type>Bool</Type>
<CheckModified>false</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>true</ClearDaily>
</Field>
</FieldAttrs>
</config>
特别要注意两件事:
- 新文件中某些元素的现有值已更改,以及 新
- 文件中添加了新元素。
鉴于上述文件,我希望输出如下所示:
<config xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
<Comment>This file was automatically generated.</Comment>
<FieldAttrs>
<Name>FieldAttrsAll</Name>
<Field>
<Name>wLegExchInstIds</Name>
<Fid>6203</Fid>
<Type>StringVector</Type>
<CheckModified>true</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>false</ClearDaily>
</Field>
<Field>
<Name>wPartitionId</Name>
<Fid>5886</Fid>
<Type>Integer</Type>
<CheckModified>true</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>false</ClearDaily>
</Field>
<Field>
<Name>wUnverifiedPriceIndicator</Name>
<Fid>5885</Fid>
<Type>Bool</Type>
<CheckModified>true</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>true</ClearDaily>
</Field>
<Field>
<Name>wCorrIsIrregular</Name>
<Fid>5884</Fid>
<Type>Bool</Type>
<CheckModified>false</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>true</ClearDaily>
</Field>
</FieldAttrs>
</config>
请考虑以下使用 document()
函数从外部 XML 进行分析的 XSLT。此方法实际上从较大的 XML 文件解析较短的 XML 中的值开始,以删除重复项,而不是添加不同的节点:
XSLT (另存为 .xsl 文件,引用第二个 XML 文件,该文件与第一个文件保存在同一个目录中)
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" 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="FieldAttrs">
<xsl:copy>
<xsl:copy-of select="Name"/>
<xsl:copy-of select="document('ShorterXML.xml')/config/FieldAttrs/Field"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="Field[Name=document('ShorterXML.xml')/config/FieldAttrs/Field/Name]"/>
</xsl:transform>
Linux 命令行(仅引用其中一个 XML 文件作为输入,全部在同一目录中)
xsltproc transform.xsl LongerXML.xml -o output.xml
输出
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
<Comment>This file was automatically generated.</Comment>
<FieldAttrs>
<Name>FieldAttrsAll</Name>
<Field>
<Name>wLegExchInstIds</Name>
<Fid>6203</Fid>
<Type>StringVector</Type>
<CheckModified>true</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>false</ClearDaily>
</Field>
<Field>
<Name>wPartitionId</Name>
<Fid>5886</Fid>
<Type>Integer</Type>
<CheckModified>true</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>false</ClearDaily>
</Field>
<Name>FieldAttrsAll</Name>
<Field>
<Name>wUnverifiedPriceIndicator</Name>
<Fid>5885</Fid>
<Type>Bool</Type>
<CheckModified>true</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>true</ClearDaily>
</Field>
<Field>
<Name>wCorrIsIrregular</Name>
<Fid>5884</Fid>
<Type>Bool</Type>
<CheckModified>false</CheckModified>
<PublishField>true</PublishField>
<ClearDaily>true</ClearDaily>
</Field>
</FieldAttrs>
</config>
我能够使用 xsh 以给定的方式合并两个文件,xsh 是 XML::LibXML 的包装器,在后台使用libxml2
:
my $old := open old.xml ;
$field := hash Name //Field ;
open new.xml ;
for //Field {
$exists = xsh:lookup('field', Name) ;
if not($exists)
copy . into $old/config/FieldAttrs ;
}
save :f merged.xml $old ;