使用XML样式表删除与另一个文件中的内容匹配的元素



我想这样转换一个xml文件:

(input.xml)
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef>
<Component Id="c1">
<File Source="!(PublishDir)FileA" />
</Component>
<Component Id="c2">
<File Source="!(PublishDir)FileB" />
</Component>
<Component Id="c3">
<File Source="!(PublishDir)FileC" />
</Component>
<Component Id="c4">
<File Source="!(PublishDir)FileD" />
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup>
<ComponentRef Id="c1" />
<ComponentRef Id="c2" />
<ComponentRef Id="c3" />
<ComponentRef Id="c4" />
</ComponentGroup>
</Fragment>
</Wix>

这是heat的简化输出,wix (Windows Installer XML)收集器。但这不会有什么不同。

应该从原始xml中删除一些不需要的文件(包括Component和ComponentRef标签)。其中一些文件是预先知道的(FileA),有些文件名在文件中,像这样:

(filelist.xml)
<Files>
<File>FileB</File>
<File>FileC</File>
</Files>

结果应该是这样的:

(output.xml)
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef>
<Component Id="c4">
<File Source="!(PublishDir)FileD" />
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup>
<ComponentRef Id="c4" />
</ComponentGroup>
</Fragment>
</Wix>

提前删除已知的文件很简单,下面是我目前所做的:

(stylesheet.xsl)
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
xmlns="http://schemas.microsoft.com/wix/2006/wi">
<!-- identity transform -->
<xsl:template match="@*|*">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="*" />
</xsl:copy>
</xsl:template>
<xsl:output method="xml" indent="yes" />
<!-- remove files -->
<xsl:key name="file-search" match="wix:Component[substring(wix:File/@Source, string-length(wix:File/@Source) - 4) = 'FileA']" use="@Id"/>
<xsl:template match="wix:Component[key('file-search', @Id)]" />
<xsl:template match="wix:ComponentRef[key('file-search', @Id)]" />
</xsl:stylesheet>

但是"filelist.xml"reomoved吗?这是我尝试过的,但这不起作用(变量不允许在匹配)

<xsl:variable name="filelist" select="document('filelist.xml')"/>
<xsl:key name="file-search" match="wix:Component[contains($filelist, substring-after(wix:File/@Source, ''))]" use="@Id"/>

XSLT 1.0解决方案更可取,因为工具支持它,但我也可以使用带有一些附加连接的XSLT 2.0。

在XSLT 1.0中这样做时面临的主要障碍是:(a)键不能跨文档工作,(b)不能在匹配模式中使用变量。

也许你可以这样做:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
exclude-result-prefixes="wix">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="component-by-filename" match="wix:Component" use="substring-after(wix:File/@Source, '')" />
<xsl:variable name="exclude-ids" select="key('component-by-filename', 'FileA')/@Id | key('component-by-filename', document('filelist.xml')/Files/File)/@Id "/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="wix:DirectoryRef | wix:ComponentGroup">
<xsl:copy>
<xsl:apply-templates select="*[not(@Id = $exclude-ids)]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>