英文:
Group unique records combined with list of values
问题
I have translated the text as requested:
我刚刚开始使用XSLT工作,并且遇到了一个问题,需要将XML数据转换为XSL样式表。
我希望下面的内容能够清楚:
我有3行记录,黄色标记的区域是代码的第一部分,所有标记中的值都相同。
此区域之后的值在每个值日期中都不同。
我想要创建一种根据黄色标记数据的唯一集合创建分组,然后创建“quote”部分中不同值的列表。
我添加了一个示例,说明了我希望的最终结果。
我不知道在论坛中搜索什么关键词来获取解决我的问题的提示 - 这对于像我这样的新手是否可能修复?
只想提一下,我已经得到了创建代码的主要部分的帮助,但我理解这段代码,可以对其进行小的调整。
提前感谢您能提供的任何帮助。
以下是代码部分:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8" />
<xsl:template match="/">
<Import>
<Funds>
<xsl:for-each select="//Record">
<Fund>
<xsl:attribute name="Id">
<xsl:value-of select="./Fund_Id/text()" />
</xsl:attribute>
<FundData>
<xsl:attribute name="Name">
<xsl:value-of select="./FundData/text()" />
</xsl:attribute>
<xsl:for-each select="./*[not(name() = 'Fund_Id') and not(name() = 'FundData') and not(name() = 'NetAssetValue') and not(name() = 'Description')]">
<xsl:variable name="attribute">
<xsl:value-of select="name()" />
</xsl:variable>
<xsl:attribute name="{$attribute}">
<xsl:value-of select="./text()" />
</xsl:attribute>
</xsl:for-each>
</FundData>
<Quote>
<xsl:attribute name="ValueDate2">
<xsl:value-of select="./ValueDate/text()" />
</xsl:attribute>
<xsl:attribute name="Value">
<xsl:value-of select="./Value/text()" />
</xsl:attribute>
</Quote>
</Fund>
</xsl:for-each>
</Funds>
</Import>
</xsl:template>
</xsl:stylesheet>
我已经翻译了您的要求部分,如有需要,请随时提出其他问题。
英文:
I am very new into working with XSLT and has an issue where we have to convert XML data into an XSL stylesheet.
I hope below makes sense:
I have 3 line of records where the area marked with yellow is the first part of the code and is the same values in all tags.
The values after this area is different per each value date.
I want to create a kind of grouping per unique set of the yellow marked data and then create a list of the different values in the "quote" section.
I have added and example of how I would like the end result to be.
I have no idea what to search for in the forum to get a hint to fix my issue - and is it possible to fix for a newbie as me?
Just want to mention that I have had help to create the mainpart of the code but I understand the code and I am able to make small adjustments to it.
Thanks in advance for any help I can get.
Code is as follows
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8" />
<xsl:template match="/">
<Import>
<Funds>
<xsl:for-each select="//Record">
<Fund>
<xsl:attribute name="Id">
<xsl:value-of select="./Fund_Id/text()" />
</xsl:attribute>
<FundData>
<xsl:attribute name="Name">
<xsl:value-of select="./FundData/text()" />
</xsl:attribute>
<xsl:for-each select="./*[not(name() = 'Fund_Id') and not(name() = 'FundData') and not(name() = 'NetAssetValue') and not(name() = 'Description')]">
<xsl:variable name="attribute">
<xsl:value-of select="name()" />
</xsl:variable>
<xsl:attribute name="{$attribute}">
<xsl:value-of select="./text()" />
</xsl:attribute>
</xsl:for-each>
</FundData>
<Quote>
<xsl:attribute name="ValueDate2">
<xsl:value-of select="./ValueDate/text()" />
</xsl:attribute>
<xsl:attribute name="Value">
<xsl:value-of select="./Value/text()" />
</xsl:attribute>
</Quote>
</Fund>
</xsl:for-each>
</Funds>
</Import>
</xsl:template>
</xsl:stylesheet>
Data I am using:
<Data>
<Record><Fund_Id>ABC</Fund_Id><FundData>Hello</FundData><ValueDate>2023-05-11</ValueDate><Percent>30.0181</Percent><ThemeId>9</ThemeId><Valuedate2>2023-05-09</Valuedate2><Value>149.84</Value></Record>
<Record><Fund_Id>ABC</Fund_Id><FundData>Hello</FundData><ValueDate>2023-05-11</ValueDate><Percent>30.0181</Percent><ThemeId>9</ThemeId><Valuedate2>2023-05-10</Valuedate2><Value>157.12</Value></Record>
<Record><Fund_Id>ABC</Fund_Id><FundData>Hello</FundData><ValueDate>2023-05-11</ValueDate><Percent>30.0181</Percent><ThemeId>9</ThemeId><Valuedate2>2023-05-11</Valuedate2><Value>136.07</Value></Record>
</Data>
The result I am looking for
<?xml version="1.0" encoding="UTF-8"?>
<Import>
<Funds>
</Fund>
<Fund Id="ABC">
<FundData Name="Hello" ValueDate="2023-05-11" Percent="30.01810"ThemeId="9"/>
<Quote ValueDate="2023-05-09" Value="149.84"/>
<Quote ValueDate="2023-05-10" Value="157.12"/>
<Quote ValueDate="2023-05-11" Value="136.07"/>
</Fund>
</Funds>
</Import>
答案1
得分: 2
请看以下翻译好的部分:
首先,让我们稍微清理一下您的代码,以使其更易阅读。您可以将此部分替换为:
<Fund Id="{Fund_Id}">
<FundData Name="{FundData}">
<xsl:for-each select="* except (FundData|NetAssetValue|Description)">
<xsl:attribute name="{name()}" select="."/>
</xsl:for-each>
</FundData>
<Quote ValueDate2="{ValueDate}" Value="{Value}"/>
</Fund>
现在,代码更易读,清楚地显示您正在为每个输入的记录创建一个 FundData
和一个 Quote
,而您想要根据共同的属性值对记录进行分组;因此,在XSLT 2.0+中,您可以使用 xsl:for-each-group
。实际上,您想要使用具有复合分组键的XSLT 3.0功能,但如果您的处理器支持XSLT 2.0,那么很有可能它也支持XSLT 3.0,因此分组将如下所示:
<xsl:for-each-group select="*"
group-by="Fund_Id, FundData, ValueDate, Percent, ThemeId"
composite="yes">
但如果您确实需要纯粹的XSLT 2.0,那么您可以构建一个简单的键,如@MartinHonnen所建议的使用字符串串联。
英文:
First, let's clean up your code a bit to make it easier to read. You can replace this:
<Fund>
<xsl:attribute name="Id">
<xsl:value-of select="./Fund_Id/text()" />
</xsl:attribute>
<FundData>
<xsl:attribute name="Name">
<xsl:value-of select="./FundData/text()" />
</xsl:attribute>
<xsl:for-each select="./*[not(name() = 'Fund_Id') and not(name() = 'FundData') and not(name() = 'NetAssetValue') and not(name() = 'Description')]">
<xsl:variable name="attribute">
<xsl:value-of select="name()" />
</xsl:variable>
<xsl:attribute name="{$attribute}">
<xsl:value-of select="./text()" />
</xsl:attribute>
</xsl:for-each>
</FundData>
<Quote>
<xsl:attribute name="ValueDate2">
<xsl:value-of select="./ValueDate/text()" />
</xsl:attribute>
<xsl:attribute name="Value">
<xsl:value-of select="./Value/text()" />
</xsl:attribute>
</Quote>
</Fund>
by this:
<Fund Id="{Fund_Id}">
<FundData Name={FundData}"
<xsl:for-each select="* except (FundData|NetAssetValue|Description)">
<xsl:attribute name="{name()}" select="."/>
</xsl:for-each>
</FundData>
<Quote ValueDate2="{ValueDate}" Value="{Value}"/>
</Fund>
Now that the code is more readable it's clear that you are creating one FundData
and one Quote
for each input Record
, whereas you want to group the records based on common attribute values; so in XSLT 2.0+ you want xsl:for-each-group
. In fact you want it with a composite grouping key, which is an XSLT 3.0 capability, but if your processor supports XSLT 2.0 then there is a very good chance that it supports XSLT 3.0, so the grouping would be
<xsl:for-each-group select="*"
group-by="Fund_Id, FundData, ValueDate, Percent, ThemeId"
composite="yes">
But if you really do need pure XSLT 2.0 then you can construct a simple key using string concatenation as suggested by @MartinHonnen.
答案2
得分: 1
为了按照 Fund_Id
、FundData
、ValueDate
、Percent
和 ThemeId
的组合值对记录进行分组,您可以使用以下 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:template match="/Data">
<Import>
<Funds>
<xsl:for-each-group select="Record" group-by="string-join((Fund_Id, FundData, ValueDate, Percent, ThemeId), '|')">
<Fund Id="{Fund_Id}">
<FundData Name="{FundData}" ValueDate="{ValueDate}" Percent="{Percent}" ThemeId="{ThemeId}"/>
<xsl:for-each select="current-group()">
<Quote ValueDate="{Valuedate2}" Value="{Value}"/>
</xsl:for-each>
</Fund>
</xsl:for-each-group>
</Funds>
</Import>
</xsl:template>
</xsl:stylesheet>
应用于您的输入示例的结果如下:
<?xml version="1.0" encoding="UTF-8"?>
<Import>
<Funds>
<Fund Id="ABC">
<FundData Name="Hello"
ValueDate="2023-05-11"
Percent="30.0181"
ThemeId="(ThemeId)"/>
<Quote ValueDate="2023-05-09" Value="149.84"/>
<Quote ValueDate="2023-05-10" Value="157.12"/>
<Quote ValueDate="2023-05-11" Value="136.07"/>
</Fund>
</Funds>
</Import>
与您展示的结果略有不同 - 但是您展示的结果本身并不是一个格式良好的 XML 文档。
请注意,在 XSLT 3.0 中,您可以简化以下部分:
<xsl:for-each-group select="Record" group-by="string-join((Fund_Id, FundData, ValueDate, Percent, ThemeId), '|')">
为:
<xsl:for-each-group select="Record" group-by="Fund_Id, FundData, ValueDate, Percent, ThemeId" composite="yes">
英文:
To group the records by the combined value of Fund_Id
, FundData
, ValueDate
, Percent
and ThemeId
you can do:
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:template match="/Data">
<Import>
<Funds>
<xsl:for-each-group select="Record" group-by="string-join((Fund_Id, FundData, ValueDate, Percent, ThemeId), '|')">
<Fund Id="{Fund_Id}">
<FundData Name="{FundData}" ValueDate="{ValueDate}" Percent="{Percent}" ThemeId="(ThemeId)"/>
<xsl:for-each select="current-group()">
<Quote ValueDate="{Valuedate2}" Value="{Value}"/>
</xsl:for-each>
</Fund>
</xsl:for-each-group>
</Funds>
</Import>
</xsl:template>
</xsl:stylesheet>
The result when applied to your input example:
<?xml version="1.0" encoding="UTF-8"?>
<Import>
<Funds>
<Fund Id="ABC">
<FundData Name="Hello"
ValueDate="2023-05-11"
Percent="30.0181"
ThemeId="(ThemeId)"/>
<Quote ValueDate="2023-05-09" Value="149.84"/>
<Quote ValueDate="2023-05-10" Value="157.12"/>
<Quote ValueDate="2023-05-11" Value="136.07"/>
</Fund>
</Funds>
</Import>
is slightly different than the result you show - but then the result you show is not a well-formed XML document.
Note that in XSLT 3.0 you could simplify:
<xsl:for-each-group select="Record" group-by="string-join((Fund_Id, FundData, ValueDate, Percent, ThemeId), '|')">
to:
<xsl:for-each-group select="Record" group-by="Fund_Id, FundData, ValueDate, Percent, ThemeId" composite="yes">
答案3
得分: 0
I have cleaned up my code and testet XSLT 3.0 grouping without any luck.
但是通过结合您的回答,我已经能够创建一个能够给我想要的结果的代码。
I only group by Fund_ID and Valuedate as they are the key for when the record is unique - hope it makes sense (it does in my head).
我只按Fund_ID和Valuedate分组,因为它们是记录唯一性的关键 - 希望这有意义(在我的想法中是这样的)。
I hope my comment does not get deleted even though I write I am very thankful for your assistance.
我希望我的评论不会被删除,尽管我写了我非常感谢您的帮助。
The code I will be using is this
我将使用的代码如下:
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Data">
<FundImport>
<Funds>
<xsl:for-each-group select="Record" group-by="string-join((Fund_Id, ValueDate), '|')">
<Fund Id="{Fund_Id}">
<FundData Name="{FundData}">
<xsl:for-each select="* except (Fund_Id|FundData|NetAssetValue|ValueDate2)">
<xsl:attribute name="{name()}" select="."/>
</xsl:for-each>
<xsl:attribute name="Description">
<xsl:choose>
<xsl:when test="./Description/text() = 'false'">
<xsl:value-of select="''"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="./Description/text()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</FundData>
<xsl:for-each select="current-group()">
<Quote ValueDate="{Valuedate2}" NetAssetValue="{NetAssetValue}"/>
</xsl:for-each>
</Fund>
</xsl:for-each-group>
</Funds>
</FundImport>
</xsl:template>
</xsl:stylesheet>
英文:
I have cleaned up my code and testet XSLT 3.0 grouping without any luck.
But by combining your answers I have been able to create a code that gives me the wanted result.
I only group by Fund_ID and Valuedate as they are the key for when the record is unique - hope it makes sense (it does in my head).
I hope my comment does not get deleted even though I write I am very thankful for your assistance.
The code I will be using is this
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:template match="/Data">
<FundImport>
<Funds>
<xsl:for-each-group select="Record" group-by="string-join((Fund_Id, ValueDate), '|')">
<Fund Id="{Fund_Id}">
<FundData Name="{FundData}">
<xsl:for-each select="* except (Fund_Id|FundData|NetAssetValue|ValueDate2)">
<xsl:attribute name="{name()}" select="."/>
</xsl:for-each>
<xsl:attribute name="Description">
<xsl:choose>
<xsl:when test="./Description/text() = 'false'">
<xsl:value-of select="''" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="./Description/text()" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</FundData>
<xsl:for-each select="current-group()">
<Quote ValueDate="{Valuedate2}" NetAssetValue="{NetAssetValue}"/>
</xsl:for-each>
</Fund>
</xsl:for-each-group>
</Funds>
</FundImport>
</xsl:template>
</xsl:stylesheet>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论