将来自两个 XML 个文件的信息与一个 XSL 合并

Combine information from two XML files with one XSL

我有两个 XML 文件,其中包含不同的信息:

example.xml

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="stylesheet.xsl"?>
<root>
  <Module Name="Module A">
    <Message>1</Message>
    <Message>3</Message>
  </Module>
  <Module Name="Module B">
    <Message>1</Message>
    <Message>2</Message>
    <Message>4</Message>
  </Module>
</root>

messages.xml

<?xml version="1.0" encoding="utf-8"?>
<messages>
  <message number="1">
    <description en="Message One" de="Meldung Eins" />
  </message>
  <message number="2">
    <description en="Error" de="Fehler" />
  </message>
  <message number="3">
    <description en="Warning" de="Warnung" />
  </message>
  <message number="4">
    <description en="Message XY" de="Meldung XY" />
  </message>
</messages>

现在我已经创建了一个 XSL 文件来组合信息

stylesheet.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <body>
                <h2>Messages</h2>
                <table border="1">
                    <tr bgcolor="#d3d3d3">
                        <th>Module Name</th>
                        <th>Message</th>
                        <th>Description EN</th>
                        <th>Description DE</th>
                    </tr>
                    <xsl:for-each select="//Message">
                        <tr>
                            <xsl:variable name="num">
                                <xsl:value-of select="."/>
                            </xsl:variable>
                            <td>
                                <xsl:value-of select="../@Name"/>
                            </td>
                            <td>
                                <xsl:value-of select="."/>
                            </td>
                            <xsl:for-each select="document('messages.xml')//message">
                                <xsl:choose>
                                    <xsl:when test="$num = @number">
                                        <td>
                                            <xsl:value-of select="description/@en"/>
                                        </td>
                                        <td>
                                            <xsl:value-of select="description/@de"/>
                                        </td>
                                    </xsl:when>
                                </xsl:choose>
                            </xsl:for-each>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

并得到这样的输出

Module Name Message Description EN Description DE
Module A 1 Message One Meldung Eins
Module A 3 Warning Warnung
Module B 1 Message One Meldung Eins
Module B 2 Error Fehler
Module B 4 Message XY Meldung XY

有没有比在彼此内部使用两个 for-each 更简单的方法来解决这个问题?

我正在使用 XSLT 1.0

如果只使用这两个值,则不需要 for-each。为文档定义一个变量,一个在 for-each 中,并通过 XPath 访问错误消息文本(如评论中已经提到的):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="docMsg" select="document('messages.xml')//message" />

...

<xsl:for-each select="//Message">
    <tr>
        <xsl:variable name="num" select="." />
        <td>
            <xsl:value-of select="../@Name"/>
        </td>
        <td>
            <xsl:value-of select="."/>
        </td>
        <td>
            <xsl:value-of select="$docMsg[@number=$num]/description/@en"/>
        </td>
        <td>
            <xsl:value-of select="$docMsg[@number=$num]/description/@de"/>
        </td>
    </tr>
</xsl:for-each>

但是如果你想遍历所有的属性,你可以使用 for-each:

<xsl:for-each select="//Message">
    <tr>
        <xsl:variable name="num" select="." />
        <td>
            <xsl:value-of select="../@Name"/>
        </td>
        <td>
            <xsl:value-of select="."/>
        </td>
    <xsl:for-each select="$docMsg[@number=$num]/description/@*">
        <td>
            <xsl:value-of select="."/>
        </td>
    </xsl:for-each>
    </tr>
</xsl:for-each>

这会遍历 <description> 的所有属性(每个属性一列)。但要注意属性在元素中的顺序必须始终相同。如果不是,您可以在内部 for-each 中使用 <xsl:sort select="local-name()" /> 对它们进行排序。