【问题标题】:Need to create XML based on another XML using XSLT2.0 based on distinct attributes and group by需要使用 XSLT2.0 基于不同的属性和分组依据创建基于另一个 XML 的 XML
【发布时间】:2020-04-06 17:21:01
【问题描述】:

我正在尝试生成基于其他 2 个 XML 的 XML。我正在轮询一个返回人员详细信息的数据库(查询中可以返回 n 人)。 最终的 XML 应该具有与来自 DB 的 XML 中的 不同名称标签一样的确切数量的 数据标签。例如:

第一个 XML - 从 DB 获取它

<parent>
    <child>
        <name>John</name>
        <city>Boston</city>
    </child>
    <child>
        <name>John</name>
        <city>Seattle</city>
    </child>
    <child>
        <name>Allison</name>
        <city>Houston</city>
    </child>
    <child>
        <name>John</name>
        <city>Boston</city>
    </child>
</parent>

第二个 XML - 从另一个来源获取这个

<details>
    <detail>
        <city>Boston</city>
        <code>abc</code>
    </detail>
    <detail>
        <city>Houston</city>
        <code>xyz</code>
    </detail>
</details>

首先我需要创建 2 个数据标签,因为有 2 个不同的名称(John 和 Allison),然后我需要一一检查所有 childCity 标签是否第一个 XML 中的 strong> 标签与第二个 XML 中的 匹配,然后创建 Details 标签并在最终 XML 中复制 Code 标签及其值。

1) 如果没有匹配的条目,则不应创建详细信息标签,因为没有匹配的条目。 2)不,永远不会有多个匹配条目。数据标签应基于 Distinct NAME 标签和 details 标签基于匹配城市标签的数量。

最终生成的 XML

<FinalData>
    <Data>
        <name>John</name>
        <details>
            <city>Boston</city>
            <code>xyz</code>
        </details>
    </Data>
    <Data>
        <name>Allison</name>
        <details>
            <city>Houston</city>
            <code>abc</code>
        </details>
    </Data>
</FinalData>

编辑 1:

我在填充 代码标记 时遇到问题,因为我必须匹配两个 XML 中的 城市标记,并且需要一个 for 循环进行匹配。

以下是我的尝试 -

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:param name="otherFile" select="document('SOF Input 2.xml')"/>
    <xsl:template match="parent">
        <FinalData>
            <xsl:for-each-group select="child" group-by="name">
                <data>
                    <name>
                        <xsl:value-of select="name"/>
                    </name>
                    <details>
                        <city>
                            <xsl:value-of select="city"/>
                        </city>
                        <code>
                            <xsl:for-each select="$otherFile/details/detail">
                                <xsl:if test="parent/child/city='/city'">
                                    <!--I am getting stuck here - not able to get value here..i guess both city tags are referring to the same-->
                                    <xsl:value-of select="/code"/>
                                </xsl:if>
                            </xsl:for-each>
                        </code>
                    </details>
                </data>
                <xsl:text>
</xsl:text>
            </xsl:for-each-group>
        </FinalData>
    </xsl:template>
</xsl:stylesheet>

我得到以下输出 -

<?xml version="1.0" encoding="UTF-8"?>
<FinalData><data>
        <name>John</name>
        <details>
            <city>Boston</city>
            <code/>
        </details>
    </data>
<data>
        <name>Allison</name>
        <details>
            <city>Houston</city>
            <code/>
        </details>
    </data>
</FinalData>

它的缩进也有点错误。如果我遗漏了什么,请告诉我。

编辑 2:

恐怕迈克尔提到的情况比预期的要早得多。 city 标签将重复出现,但位于 parent 标签之下。 city 标签的值在 parent 标签内是唯一的。我必须从所有匹配的 city 标记中一个接一个地获取所有父母的值,并以 parent 标记中匹配的任何内容进入相应 detail 标记。 PFB 示例 XML,可以更好地解释 -

第一个 XML -

<parent>
    <child>
        <name>John</name>
        <city>Boston</city>
    </child>
    <child>
        <name>John</name>
        <city>Seattle</city>
    </child>
    <child>
        <name>Allison</name>
        <city>Houston</city>
    </child>
    <child>
        <name>John</name>
        <city>Boston</city>
    </child>
</parent>

第二个 XML-

<details>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
</details>

最终预期的 XML-

<FinalData>
    <Data>
        <name>John</name>
        <details>
            <detail>
                <city value="Boston">abc</city>
            </detail>
            <detail>
                <city value="Boston">abc</city>
                <city value="Seattle">mno</city>
            </detail>
            <detail>
                <city value="Seattle">mno</city>
            </detail>
        </details>
    </Data>
    <Data>
        <name>Allison</name>
        <details>
            <detail>
                <city value="Houston">xyz</city>
            </detail>
            <detail>
                <city value="Houston">xyz</city>
            </detail>
        </details>
    </Data>
</FinalData>

希望这很清楚,因为我不擅长解释。

【问题讨论】:

  • 那么您的 XSLT 代码在哪里尝试使用 group-by 对第一个输入进行分组?如果第二个 XML 中没有匹配的城市或匹配的城市不止一个,会发生什么情况?
  • 这很简单,使用xsl:for-each-group 来创建Data 元素和key 用于details。发布您的尝试,以便我们了解您的具体问题所在。
  • @michael.hor257k 我现在已经粘贴了我的尝试。不确定当前代码是否仅适用于这种情况或我的意图。 :) 另一个问题是比较两个 XML 中的城市标签并放置一个 for-each 我需要检查第二个 XML 中的所有城市标签。
  • @MartinHonnen 我现在已经发布了尝试。至于您的查询 - 第二个 XML 中总会有唯一的城市。不确定将来是否会发生这种情况,但目前还没有。 :)
  • @michael.hor257k 你能帮帮我吗?

标签: xml xslt xslt-2.0 xslt-grouping


【解决方案1】:

试试这个方法?

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="otherFile" select="document('SOF Input 2.xml')"/>

<xsl:key name="detail-by-city" match="detail" use="city" />

<xsl:template match="/parent">
    <FinalData>
        <xsl:for-each-group select="child" group-by="name">
            <data>
                <xsl:copy-of select="name"/>
                <xsl:for-each select="key('detail-by-city', current-group()/city, $otherfile)">
                    <details>
                         <xsl:copy-of select="*"/>
                    </details>
                </xsl:for-each>
            </data>
        </xsl:for-each-group>
    </FinalData>
</xsl:template>

</xsl:stylesheet>

这是假设一个组在另一个文档中可以有多个匹配条目,并且您希望为每个条目创建一个单独的 details 节点。

【讨论】:

  • 我想有一个小误解 - details 标签将始终存在,因为 city 标签将来自第一个 XML,但是code 标签应该基于第二个 XML。另外,我还有一个疑问,在恰好有 1 个匹配条目的情况下,同样的工作是否可以在第二个 XML 中说 0 个匹配条目?
  • 由于city 元素在两者中是相同的,所以它来自哪里并不重要。您需要澄清如果 (1) 没有匹配的条目和 (2) 有多个匹配的条目会发生什么。如前所述,我的答案将为每个匹配条目创建一个单独的 details 元素。因此,如果没有匹配的条目,则不会有 details 元素。如果您想要其他内容,请编辑您的问题并添加更多示例。目前您的预期结果不明确。
  • 1) 如果没有匹配的条目,则应创建 details 标签,这样只会填充 city 而不会填充 代码,因为没有匹配的条目。 2)不,永远不会有多个匹配条目。详细信息标签应基于 Distinct NAME 标签创建。希望这可以清除它。
  • 不,恐怕根本不清楚。在您的示例中,输出中完全省略了西雅图市。因此,似乎如果没有匹配的条目,就没有城市。而'distinct'与此无关。如果约翰同时拥有波士顿和休斯顿呢?你想把它们放在同一个 details 元素中,而不是为每个城市/代码对包装吗?
  • 我同意你的看法。对数据感到困惑(因为我正在这样做作为 POC 的一部分)。应该根据匹配城市的数量创建详细信息标签,然后填充要填充的代码,这是有道理的。也编辑了问题。谢谢小伙伴的帮助。干杯!!
【解决方案2】:

声明一个密钥

<xsl:key name="city" match="detail" use="city"/>

然后使用

<xsl:copy-of select="key('city', city, $otherFile)/code"/>

在您的for-each-group 内输出匹配代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多