XSLT 根据值对出现进行分组
XSLT Group occurrences based on a value
我通常擅长 XSLT 编程,但这让我很困惑。我认为这与 Muenchian Grouping 有关,但我不确定,因为当我尝试时结果不是我想要的,所以我可能在这里错了。我需要将以下 XML 转换为输出 XML。我只能使用 XSLT 1.0。
输入XML
<ns2:ListOfAssetMgmt-AssetXaQe xmlns:ns2="http://system.com/CustomUI">
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>1</ns3:Id>
<ns3:Name2>Direction</ns3:Name2>
<ns3:TextValue>Injection</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>1</ns3:Id>
<ns3:Name2>MeterType</ns3:Name2>
<ns3:TextValue>YMR</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>2</ns3:Id>
<ns3:Name2>LoadProfile</ns3:Name2>
<ns3:TextValue>Wind</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>2</ns3:Id>
<ns3:Name2>Direction</ns3:Name2>
<ns3:TextValue>Rotation</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>2</ns3:Id>
<ns3:Name2>MeterType</ns3:Name2>
<ns3:TextValue>ZMR</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
</ns3:ListOfAssetMgmt-AssetXaQe>
输出XML
<Assets>
<QuotingEngineServicePointAssets>
<MeterConfigurationId>1</MeterConfigurationId>
<Direction>Injection</Direction>
<MeterType>YMR</MeterType>
<TimeOfUse></TimeOfUse>
<Segment></Segment>
<Tension></Tension>
<ReadingFrequency></ReadingFrequency>
<BillingFrequency></BillingFrequency>
<LoadProfile></LoadProfile>
<LocalProduction></LocalProduction>
<DistributionTariff></DistributionTariff>
</QuotingEngineServicePointAssets>
<QuotingEngineServicePointAssets>
<MeterConfigurationId>2</MeterConfigurationId>
<Direction>Rotation</Direction>
<MeterType>ZMR</MeterType>
<TimeOfUse></TimeOfUse>
<Segment></Segment>
<Tension></Tension>
<ReadingFrequency></ReadingFrequency>
<BillingFrequency></BillingFrequency>
<LoadProfile>Wind</LoadProfile>
<LocalProduction></LocalProduction>
<DistributionTariff></DistributionTariff>
</QuotingEngineServicePointAssets>
</Assets>
其他标签,如 TimeOfUse、Segment 等,如果它们存在于输入 XML 上,则可能也需要填充。如果它们在 Input XML 上不存在,则不应在 Output XML 上输出该元素,但我已在此处展示了可以输出的内容。非常感谢任何帮助。
我同意 michael.hor257k 的说法,即你的问题没有包含你想要实现的目标的文本描述。请始终包含它以帮助我们帮助您。
尽管如此,我查看了您的输入和输出,并认为我对示例背后的基本逻辑有所了解。
我会分 两个阶段构建流程:
- 首先,计算一个所有相关 ID 的唯一列表,为以后的工作提供一些基础。你可以例如只需遍历列表并将其存储在变量中。我使用了两个循环来保持上下文干净:
<!-- get distinct IDs, variable contains <id>1</id><id>2</id> -->
<xsl:variable name="distinctValues">
<xsl:for-each select="//AssetMgmt-AssetXaQe">
<xsl:variable name="ctx1" select="." />
<!-- filter out IDs that already occured to list them only once -->
<xsl:if test="not(preceding-sibling::AssetMgmt-AssetXaQe[Id/text() = $ctx1/Id/text()])">
<id><xsl:value-of select="$ctx1/Id/text()" /></id>
</xsl:if>
</xsl:for-each>
</xsl:variable>
- 正如@michael.hor257k 指出的那样,下面的方法会更有效,但这是我不太了解的解决方案:
<xsl:key name="AssetMgmt-by-Id" match="AssetMgmt-AssetXaQe" use="Id" />
<xsl:for-each select="AssetMgmt-AssetXaQe[count(. | key('AssetMgmt-by-Id', Id)[1]) = 1]">
<!-- do whatever needs to be done per unique ID -->
</for-each>
- 其次,您可以遍历此列表,遍历具有相应 ID 的所有项目,并动态生成基于每个 (using
xslt:element
) 命名的标签 Name2
-标签内容:
<xsl:variable name="$ctx2" select="." />
<xsl:for-each select="$distinctValues">
<QuotingEngineServicePointAssets>
<MeterConfigurationId>
<xsl:value-of select="." />
</MeterConfigurationId>
<!-- iterate over all the entries that belong to this ID -->
<xsl:for-each select="$ctx2//AssetMgmt-AssetXaQe[Id/text() = .]">
<!-- dynamically generate tags based on the content of the Name2-Tag -->
<xsl:element name="{./Name2}">
<xsl:value-of select="./TextValue">
</xsl:element>
</xsl:for-each>
</QuotingEngineServicePointAssets>
</xsl:for-each>
这应该可以解决问题。我把命名空间的麻烦留给你了,祝你好运!
我通常擅长 XSLT 编程,但这让我很困惑。我认为这与 Muenchian Grouping 有关,但我不确定,因为当我尝试时结果不是我想要的,所以我可能在这里错了。我需要将以下 XML 转换为输出 XML。我只能使用 XSLT 1.0。
输入XML
<ns2:ListOfAssetMgmt-AssetXaQe xmlns:ns2="http://system.com/CustomUI">
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>1</ns3:Id>
<ns3:Name2>Direction</ns3:Name2>
<ns3:TextValue>Injection</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>1</ns3:Id>
<ns3:Name2>MeterType</ns3:Name2>
<ns3:TextValue>YMR</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>2</ns3:Id>
<ns3:Name2>LoadProfile</ns3:Name2>
<ns3:TextValue>Wind</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>2</ns3:Id>
<ns3:Name2>Direction</ns3:Name2>
<ns3:TextValue>Rotation</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
<ns3:AssetMgmt-AssetXaQe xmlns:ns3="http://www.system.com/xml/QE%20%%20%Points">
<ns3:Id>2</ns3:Id>
<ns3:Name2>MeterType</ns3:Name2>
<ns3:TextValue>ZMR</ns3:TextValue>
</ns3:AssetMgmt-AssetXaQe>
</ns3:ListOfAssetMgmt-AssetXaQe>
输出XML
<Assets>
<QuotingEngineServicePointAssets>
<MeterConfigurationId>1</MeterConfigurationId>
<Direction>Injection</Direction>
<MeterType>YMR</MeterType>
<TimeOfUse></TimeOfUse>
<Segment></Segment>
<Tension></Tension>
<ReadingFrequency></ReadingFrequency>
<BillingFrequency></BillingFrequency>
<LoadProfile></LoadProfile>
<LocalProduction></LocalProduction>
<DistributionTariff></DistributionTariff>
</QuotingEngineServicePointAssets>
<QuotingEngineServicePointAssets>
<MeterConfigurationId>2</MeterConfigurationId>
<Direction>Rotation</Direction>
<MeterType>ZMR</MeterType>
<TimeOfUse></TimeOfUse>
<Segment></Segment>
<Tension></Tension>
<ReadingFrequency></ReadingFrequency>
<BillingFrequency></BillingFrequency>
<LoadProfile>Wind</LoadProfile>
<LocalProduction></LocalProduction>
<DistributionTariff></DistributionTariff>
</QuotingEngineServicePointAssets>
</Assets>
其他标签,如 TimeOfUse、Segment 等,如果它们存在于输入 XML 上,则可能也需要填充。如果它们在 Input XML 上不存在,则不应在 Output XML 上输出该元素,但我已在此处展示了可以输出的内容。非常感谢任何帮助。
我同意 michael.hor257k 的说法,即你的问题没有包含你想要实现的目标的文本描述。请始终包含它以帮助我们帮助您。
尽管如此,我查看了您的输入和输出,并认为我对示例背后的基本逻辑有所了解。
我会分 两个阶段构建流程:
- 首先,计算一个所有相关 ID 的唯一列表,为以后的工作提供一些基础。你可以例如只需遍历列表并将其存储在变量中。我使用了两个循环来保持上下文干净:
<!-- get distinct IDs, variable contains <id>1</id><id>2</id> -->
<xsl:variable name="distinctValues">
<xsl:for-each select="//AssetMgmt-AssetXaQe">
<xsl:variable name="ctx1" select="." />
<!-- filter out IDs that already occured to list them only once -->
<xsl:if test="not(preceding-sibling::AssetMgmt-AssetXaQe[Id/text() = $ctx1/Id/text()])">
<id><xsl:value-of select="$ctx1/Id/text()" /></id>
</xsl:if>
</xsl:for-each>
</xsl:variable>
- 正如@michael.hor257k 指出的那样,下面的方法会更有效,但这是我不太了解的解决方案:
<xsl:key name="AssetMgmt-by-Id" match="AssetMgmt-AssetXaQe" use="Id" />
<xsl:for-each select="AssetMgmt-AssetXaQe[count(. | key('AssetMgmt-by-Id', Id)[1]) = 1]">
<!-- do whatever needs to be done per unique ID -->
</for-each>
- 其次,您可以遍历此列表,遍历具有相应 ID 的所有项目,并动态生成基于每个 (using
xslt:element
) 命名的标签Name2
-标签内容:
<xsl:variable name="$ctx2" select="." />
<xsl:for-each select="$distinctValues">
<QuotingEngineServicePointAssets>
<MeterConfigurationId>
<xsl:value-of select="." />
</MeterConfigurationId>
<!-- iterate over all the entries that belong to this ID -->
<xsl:for-each select="$ctx2//AssetMgmt-AssetXaQe[Id/text() = .]">
<!-- dynamically generate tags based on the content of the Name2-Tag -->
<xsl:element name="{./Name2}">
<xsl:value-of select="./TextValue">
</xsl:element>
</xsl:for-each>
</QuotingEngineServicePointAssets>
</xsl:for-each>
这应该可以解决问题。我把命名空间的麻烦留给你了,祝你好运!