【问题标题】:Use an attribute from another XML in a different attribute in another XML在另一个 XML 的不同属性中使用来自另一个 XML 的属性
【发布时间】:2014-04-09 09:13:52
【问题描述】:

我使用来自 Wix 工具集的 Heat 为我的安装程序生成组件,但我的安装程序很少是 Per-User,因此我无法使用 Heat 的 Autogenerate Guids。我可以随机生成 GUID,但由于组件规则,我不希望这样做。

所以我有一个包含文件列表的 XML,这些文件应该以不同的结构包含在安装中,而不是我为每个文件添加静态 guid 的生成文件。 我想要做的是匹配我的 XML 和生成的 XML 之间的filename 并将 GUID 插入到我生成的 XML 中。

这是一个没有任何转换的xml示例:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="Dir_Sample">
            <Directory Id="Folder1" Name="Folder1">
                <Component Id="NewTextFile0.txt" Guid="PUT-GUID-HERE">
                    <File Id="NewTextFile0.txt" KeyPath="yes" Source="$(var.sample)\Folder1\NewTextFile0.txt" />
                </Component>
            </Directory>
        </DirectoryRef>
    </Fragment>
    <Fragment>
        <ComponentGroup Id="CG_Sample">
            <ComponentRef Id="NewTextFile0.txt" />
        </ComponentGroup>
    </Fragment>
</Wix>

这是我的自定义 XML,每个文件都有 GUID:

<?xml version="1.0" encoding="utf-8"?>
<FileSystemList>
  <File Path="\Programs\Folder1\NewTextFile0.txt" Guid="52B62A6E-DD87-424A-8296-3AA00E74AEF8" />
</FileSystemList>

所以当文件名和父文件夹在两个 XML 上匹配时,我希望将 Guid="PUT-GUID-HERE" 替换为 Guid="52B62A6E-DD87-424A-8296-3AA00E74AEF8"

我正在尝试了解 XSL,但我所能实现的只是脱发。我和我剩下的头发将不胜感激。

更新: 这两个xml文件的匹配应该在第一个文件的Source和第二个文件的Path上进行。

Source="$(var.sample)\Folder1\NewTextFile0.txt" 文件名(NewTextFile0.txt)和父文件夹(Folder1)在一个项目中是唯一的。 Path="\Programs\Folder1\NewTextFile0.txt" 文件名和父文件夹也是唯一的。

【问题讨论】:

  • 您使用 XSLT 1.0 处理器还是 XSLT 2.0 处理器(如 Saxon 9)?使用 XSLT 2.0,很简单地分解一个字符串并比较像该文件路径这样的子字符串,并且很容易在文档之间交叉引用,而使用 XSLT 1.0,因为基于子串很难表达。
  • 不幸的是它是 1.0 版

标签: xslt wix heat


【解决方案1】:

尝试类似:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wi="http://schemas.microsoft.com/wix/2006/wi">
<xsl:output method="xml" 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>

<!-- insert GUID -->    
<xsl:template match="wi:Component/@Guid">
    <xsl:variable name="path" select="concat(../../@Name, '\', ../@Id)" />
    <xsl:attribute name="Guid">
        <xsl:value-of select="document('FileList.xml')/FileSystemList/File[contains(@Path, $path)]/@Guid"/>
    </xsl:attribute>
</xsl:template>

</xsl:stylesheet>

编辑:

要根据Component/File/@Source 的内容进行匹配,请将$path 变量的定义更改为:

<xsl:variable name="path" select="substring-after(../wi:File/@Source, ')')" />

这是假设Source 属性中第一个“)”之后的任何内容都是存储在另一个文件中的路径的一部分。

【讨论】:

  • 太棒了!非常感谢:)
  • 如果我希望pathSource 中的&lt;File Id="NewTextFile0.txt" KeyPath="yes" Source="$(var.sample)\Folder1\NewTextFile0.txt" /&gt; 匹配,我该怎么做?
  • @IlirB 这取决于 Source 将包含什么。一个例子不足以建立一个规则。也许你应该编辑你的问题并澄清。另外,Component 的 File 子节点会不会只有一个?
  • 是的,总是一个文件:一个组件。我希望在源而不是 ID 上执行匹配的原因是因为该源将始终具有准确和正确的文件名,而 ID 不一定包含文件名,它可以是随机的。
  • @IlirB 你还没有回答我的第一个问题:Source 究竟包含哪些我们可以依赖的内容?在您的示例中,部分路径之前有 $(var.sample) 。这个确切的字符串会总是在那里吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
相关资源
最近更新 更多