XSLT将兄弟节点组合成1个记录

时间:2013-08-15 17:02:06

标签: xslt xslt-1.0 filemaker xslt-grouping

尝试学习如何使用XLS / XLST将数据导入Filemaker。我有基础知识,但现在我需要优化。

目前我有大约11组数据分裂成兄弟姐妹,我需要在导入过程中将其合并为一条记录。现在,我使用11个单独的xsl文件导入11个单独导入的数据,每个文件关注一组特定的数据(火数,命中数,分数等)。这非常低效,但我缺乏使用XLST更详细地工作的技术诀窍,并将碎片数据合并到一个记录中。

我正在使用的数据示例如下:

<character_list limit="0" returned="2" milliseconds="0">
<character id="5428010618020696081" active_profile_id="15" faction_id="3" head_id="1" title_id="0">
<stats>
<weapon_stat_list>
<weapon_stat item_id="25003" last_save="1354544215" last_save_date="2012-12-03 14:16:55.0" stat_name="weapon_fire_count" value="108" vehicle_id="0"/>
<weapon_stat item_id="25003" last_save="1354544215" last_save_date="2012-12-03 14:16:55.0" stat_name="weapon_hit_count" value="60" vehicle_id="0"/>
<weapon_stat item_id="125" last_save="1354564613" last_save_date="2012-12-03 19:56:53.0" stat_name="weapon_fire_count" value="7708" vehicle_id="0"/>
<weapon_stat item_id="125" last_save="1354564613" last_save_date="2012-12-03 19:56:53.0" stat_name="weapon_play_time" value="13406" vehicle_id="0"/>
<weapon_stat item_id="125" last_save="1354564613" last_save_date="2012-12-03 19:56:53.0" stat_name="weapon_score" value="62012" vehicle_id="0"/>
<weapon_stat item_id="1259" last_save="1354573520" last_save_date="2012-12-03 22:25:20.211913" stat_name="weapon_fire_count" value="22" vehicle_id="0"/>
</weapon_stat_list>
</stats>
</character>
<character id="5428010618040144225" active_profile_id="6" faction_id="2" head_id="1" title_id="80">
<stats>
<weapon_stat_list>
<weapon_stat item_id="126" last_save="1353442416" last_save_date="2012-11-20 20:13:36.0" stat_name="weapon_fire_count" value="130" vehicle_id="0"/>
<weapon_stat item_id="126" last_save="1353442416" last_save_date="2012-11-20 20:13:36.0" stat_name="weapon_play_time" value="336" vehicle_id="0"/>
<weapon_stat item_id="126" last_save="1353442416" last_save_date="2012-11-20 20:13:36.0" stat_name="weapon_score" value="570" vehicle_id="0"/>
<weapon_stat item_id="1260" last_save="1353442416" last_save_date="2012-11-20 20:13:36.099928" stat_name="weapon_fire_count" value="181" vehicle_id="0"/>
<weapon_stat item_id="1260" last_save="1353442416" last_save_date="2012-11-20 20:13:36.100053" stat_name="weapon_play_time" value="471" vehicle_id="0"/>
<weapon_stat item_id="1260" last_save="1353442416" last_save_date="2012-11-20 20:13:36.100189" stat_name="weapon_score" value="635" vehicle_id="0"/>
<weapon_stat item_id="1261" last_save="1353447137" last_save_date="2012-11-20 21:32:17.0" stat_name="weapon_fire_count" value="321" vehicle_id="0"/>
<weapon_stat item_id="1261" last_save="1353447137" last_save_date="2012-11-20 21:32:17.0" stat_name="weapon_play_time" value="442" vehicle_id="0"/>
<weapon_stat item_id="1261" last_save="1353447137" last_save_date="2012-11-20 21:32:17.0" stat_name="weapon_score" value="1228" vehicle_id="0"/>
</weapon_stat_list>
</stats>
</character>
</character_list>

每个角色武器数据记录的唯一标识符是角色ID,物品ID和车辆ID的组合。片段中的数据类型由“stat_name”属性确定。

我需要的输出的要点是:

<ROW MODID="1" RECORDID="1" >
    <COL><DATA>5428010618020696081</DATA></COL>
    <COL><DATA>25003</DATA></COL>
    <COL><DATA>0</DATA></COL>
    <COL><DATA>108</DATA></COL>
    <COL><DATA>60</DATA></COL>
    <COL><DATA></DATA></COL>
</ROW>
<ROW MODID="2" RECORDID="2" >
    <COL><DATA>5428010618020696081</DATA></COL>
    <COL><DATA>125</DATA></COL>
    <COL><DATA>0</DATA></COL>
    <COL><DATA>7708</DATA></COL>
    <COL><DATA></DATA></COL>
    <COL><DATA>13406</DATA></COL>
    <COL><DATA>62012</DATA></COL>
</ROW>
<ROW MODID="3" RECORDID="3" >
    <COL><DATA>5428010618020696081</DATA></COL>
    <COL><DATA>1259</DATA></COL>
    <COL><DATA>0</DATA></COL>
    <COL><DATA>22</DATA></COL>
    <COL><DATA></DATA></COL>
    <COL><DATA></DATA></COL>
    <COL><DATA></DATA></COL>
</ROW>
<ROW MODID="4" RECORDID="4" >
    <COL><DATA>5428010618040144225</DATA></COL>
    <COL><DATA>126</DATA></COL>
    <COL><DATA>0</DATA></COL>
    <COL><DATA>130</DATA></COL>
    <COL><DATA></DATA></COL>
    <COL><DATA>336</DATA></COL>
    <COL><DATA>570</DATA></COL>
</ROW>
<ROW MODID="5" RECORDID="5" >
    <COL><DATA>5428010618040144225</DATA></COL>
    <COL><DATA>1260</DATA></COL>
    <COL><DATA>0</DATA></COL>
    <COL><DATA>181</DATA></COL>
    <COL><DATA></DATA></COL>
    <COL><DATA>471</DATA></COL>
    <COL><DATA>635</DATA></COL>
</ROW>
<ROW MODID="6" RECORDID="6" >
    <COL><DATA>5428010618040144225</DATA></COL>
    <COL><DATA>1261</DATA></COL>
    <COL><DATA>0</DATA></COL>
    <COL><DATA>321</DATA></COL>
    <COL><DATA></DATA></COL>
    <COL><DATA>442</DATA></COL>
    <COL><DATA>1228</DATA></COL>
</ROW>

当然有更多列,但为简单起见省略。输出示例在各自的顺序中包含角色ID,项目ID,车辆ID,火力计数,命中计数,游戏时间,分数的“字段”。

这是我目前用于导入点击次数

的XSL文件的副本
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://tempuri.org/test.xsd">
        <xsl:template match="/character_list">
                <FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
                        <ERRORCODE>0</ERRORCODE>
                        <PRODUCT BUILD="" NAME="SOE API XML Import" VERSION="2.0" />
                        <DATABASE DATEFORMAT="yyyy.MM.dd" LAYOUT="" NAME="" RECORDS="" TIMEFORMAT="k:mm:ss" />
                        <METADATA>
                                <FIELD EMPTYOK="NO" MAXREPEAT="1" NAME="Character_ID" TYPE="TEXT" />
                                <FIELD EMPTYOK="NO" MAXREPEAT="1" NAME="Item_ID" TYPE="TEXT" />
                                <FIELD EMPTYOK="NO" MAXREPEAT="1" NAME="Vehicle_ID" TYPE="TEXT" />
                                <FIELD EMPTYOK="NO" MAXREPEAT="1" NAME="Value" TYPE="TEXT" />
                        </METADATA>
                        <RESULTSET>
                        <xsl:for-each select="character" >
                                <xsl:variable name="cid">
                                        <xsl:value-of select="@id" />
                                </xsl:variable>
                                <xsl:for-each select="stats/weapon_stat_list/weapon_stat[@stat_name='weapon_hit_count']" >
                                        <xsl:variable name="c">
                                                <xsl:value-of select="position()" />
                                        </xsl:variable>
                                        <ROW MODID="$c" RECORDID="$c" >
                                                <COL><DATA><xsl:value-of select="$cid" /></DATA></COL>
                                                <COL><DATA><xsl:value-of select="@item_id" /></DATA></COL>
                                                <COL><DATA><xsl:value-of select="@vehicle_id" /></DATA></COL>
                                                <COL><DATA><xsl:value-of select="@value" /></DATA></COL>
                                        </ROW>
                                </xsl:for-each>
                        </xsl:for-each>
                        </RESULTSET>
                </FMPXMLRESULT>
    </xsl:template>
</xsl:stylesheet>

在阅读时,似乎我可能需要使用for-each-group将信息组合在一起。我将继续尝试并弄清楚我需要做些什么来完成这项工作,但我希望有人可以节省我一些时间。我也不知道XLST Filemaker 12支持哪个版本。如果我发现更多内容,我会保持更新。

1 个答案:

答案 0 :(得分:0)

如果你可以迭代统计条目的所有键(从你的评论中,键都是item_id + vehicle_id个值对),聚合所有属于的属性应该很容易一次性完成每个键。

根据您的预期输出,对于每个键,似乎只有一个<weapon_stat>元素与stat_name='weapon_fire_count'。鉴于这是正确的,您可以通过迭代这些item_id元素轻松获取所有<weapon_stat>值:

<xsl:for-each select="stats/weapon_stat_list/weapon_stat[@stat_name='weapon_fire_count']" >

通过这些元素,可以直接生成输出字段Item ID,Vehicle ID和Fire Count。对于其他三个字段,您可以使用以下(更高级的)XPath表达式从相应的兄弟中选择值:

<xsl:value-of select="../weapon_stat[@stat_name='weapon_hit_count' and @item_id=current()/@item_id and @vehicle_id=current()/@vehicle_id]/@value" />

诀窍是比较各个上下文节点的@item_id@vehicle_id(这些都是兄弟姐妹:../weapon_stat)与@item_id@vehicle_id当前节点(由上面的for-each选择的节点)。

总而言之,您希望用以下内容替换XSL文件的内部for-each

<xsl:for-each select="stats/weapon_stat_list/weapon_stat[@stat_name='weapon_fire_count']" >
    <ROW>
        <COL><DATA><xsl:value-of select="$cid" /></DATA></COL>
        <COL><DATA><xsl:value-of select="@item_id" /></DATA></COL>
        <COL><DATA><xsl:value-of select="@vehicle_id" /></DATA></COL>
        <COL><DATA><xsl:value-of select="@value" /></DATA></COL>
        <COL><DATA><xsl:value-of select="../weapon_stat[@stat_name='weapon_hit_count' and @item_id=current()/@item_id and @vehicle_id=current()/@vehicle_id]/@value" /></DATA></COL>
        <COL><DATA><xsl:value-of select="../weapon_stat[@stat_name='weapon_play_time' and @item_id=current()/@item_id and @vehicle_id=current()/@vehicle_id]/@value" /></DATA></COL>
        <COL><DATA><xsl:value-of select="../weapon_stat[@stat_name='weapon_score' and @item_id=current()/@item_id and @vehicle_id=current()/@vehicle_id]/@value" /></DATA></COL>
    </ROW>
</xsl:for-each>

注意:我省略了MODIDRECORDID计数器,因为没有有效的解决方案可以在此转换中添加它们。但是,直接获取此转换的结果并通过第二个XSL转换添加计数器。


更新:在评论中提供的pastebin example中,似乎并非每个密钥都有weapon_fire_count个统计信息。因此,不是仅对这些统计条目进行迭代,而是需要迭代所有统计信息,如果已经存在具有相同密钥的前一个兄弟,则省略输出:

<xsl:for-each select="stats/weapon_stat_list/weapon_stat" >
    <xsl:if test="not(boolean(preceding-sibling::weapon_stat[@item_id=current()/@item_id and @vehicle_id=current()/@vehicle_id]))">
        <ROW >
            <COL><DATA><xsl:value-of select="$cid" /></DATA></COL>
            <COL><DATA><xsl:value-of select="@item_id" /></DATA></COL>
            <COL><DATA><xsl:value-of select="@vehicle_id" /></DATA></COL>
            <COL><DATA><xsl:value-of select="../weapon_stat[@stat_name='weapon_fire_count' and @item_id=current()/@item_id and @vehicle_id=current()/@vehicle_id]/@value" /></DATA></COL>
            <COL><DATA><xsl:value-of select="../weapon_stat[@stat_name='weapon_hit_count' and @item_id=current()/@item_id and @vehicle_id=current()/@vehicle_id]/@value" /></DATA></COL>
            <COL><DATA><xsl:value-of select="../weapon_stat[@stat_name='weapon_play_time' and @item_id=current()/@item_id and @vehicle_id=current()/@vehicle_id]/@value" /></DATA></COL>
            <COL><DATA><xsl:value-of select="../weapon_stat[@stat_name='weapon_score' and @item_id=current()/@item_id and @vehicle_id=current()/@vehicle_id]/@value" /></DATA></COL>
        </ROW>
    </xsl:if>
</xsl:for-each>