首页 > 解决方案 > 在 XSLT 版本 1 中是否可以通过键连接 2 个 xml 文件但输入中没有它们?

问题描述

假设我们有 2 个 XML 文件 a.xml:

<Reports>
<Fields>
 <PositionID>000101</PositionID>
 <Date>2021-04-19</Date>
 <Name>XXX</Name>
</Fields>
<Fields>
 <PositionID>000100</PositionID>
 <Date>2021-04-19</Date>
 <Name></Name>
</Fields>
</Reports>

和 b.xml:

    <AOID>
      <Employee>
        <Name>YYY</Name>
        <PositionID>000100</PositionID>
      </Employee>
      <Employee>
        <Name>XXX</Name>
        <PositionID>000101</PositionID>
      </Employee>
    </AOID>

我正在寻找一个 v1 xslt,它将通过 PositionID 加入两个提取,并从 xml b 添加 Name 字段,如果它是空的或在 XML a 中不存在。

我遇到的问题是这些都不是输入,而是我将它们放在如下变量中:

<xsl:variable name="ExtractA" select="document('a.xml')" /> <xsl:variable name="ExtractB" select="document('b.xml')" />

不幸的是,我无法让它在 xslt v1 中工作,但由于我使用的平台的一些限制,我需要它。

我在 v3 xslt 中有一个工作示例用于测试,所以我需要 v1 中的相同功能:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:variable name="ExtractA">
    <Reports>
<Fields>
 <PositionID>000101</PositionID>
 <Date>2021-04-19</Date>
 <Name></Name>
</Fields>
<Fields>
 <PositionID>000100</PositionID>
 <Date>2021-04-19</Date>
 <Name></Name>
</Fields>
</Reports>
    </xsl:variable>
    <xsl:variable name="ExtractB">
    <AOID>
      <Employee>
        <Name>YYY</Name>
        <PositionID>000100</PositionID>
      </Employee>
      <Employee>
        <Name>XXX</Name>
        <PositionID>000101</PositionID>
      </Employee>
    </AOID>
    </xsl:variable>


<xsl:template match="/">

          <xsl:if test="$ExtractA/Reports[1]/Fields[1]/Name != ''">
              <xsl:copy-of select="$ExtractA" />
          </xsl:if>
          <xsl:if test="$ExtractA/Reports[1]/Fields[1]/Name = ''">
<Reports>
             <xsl:for-each-group select="$ExtractA/Reports/Fields, $ExtractB/AOID/Employee" group-by="PositionID">
                                      <xsl:copy>
                                          <xsl:copy-of select="current-group()[1]/Date, PositionID, current-group()[2]/Name"/>
                                      </xsl:copy>
                      </xsl:for-each-group>
</Reports>

          </xsl:if>

</xsl:template>
</xsl:stylesheet>

标签: xmljoinxslt

解决方案


您可以在没有说明的情况下做得更好xsl:key

<xsl:variable name="ExtractA" select="document('a.xml')" /> 
<xsl:variable name="ExtractB" select="document('b.xml')" />

<xsl:template match="/">
    <Reports>
        <xsl:for-each select="$ExtractA/Reports/Fields">
            <Fields>
                <xsl:variable name="curItemID" select="PositionID" />
                <xsl:variable name="secItem"   select="$ExtractB/AOID/Employee[PositionID=$curItemID]" />
                <xsl:choose>
                    <xsl:when test="not(normalize-space(Name))">
                        <xsl:copy-of select="$secItem/Name" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:copy-of select="Name" />
                    </xsl:otherwise>
                </xsl:choose>
                <xsl:copy-of select="Date" />
                <xsl:copy-of select="PositionID" />
            </Fields>
        </xsl:for-each>
    </Reports>
</xsl:template>

该表达式not(normalize-space(Name))匹配空字符串或不存在的元素。
您的样本的输出是

<Reports>
    <Fields>
        <Name>XXX</Name>
        <Date>2021-04-19</Date>
        <PositionID>000101</PositionID>
    </Fields>
    <Fields>
        <Name>YYY</Name>
        <Date>2021-04-19</Date>
        <PositionID>000100</PositionID>
    </Fields>
</Reports>

这种方法的缺点是,输出仅包含文件 A 中的项目。如果文件 B 包含更多项目,它们将被忽略。


推荐阅读