XLST将兄弟节点合并为1个记录



尝试学习如何使用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>

在阅读过程中,我似乎需要为每个小组使用一个来将信息分组在一起。我会继续努力,弄清楚我需要做些什么来实现这一目标,但我希望有人能为我节省一些时间。我也不知道XLST Filemaker 12支持什么版本。如果我发现更多,我会不断更新。

如果您可以迭代stat条目的所有键(根据您的注释,这些键都是item_id+vehicle_id值对),那么一次聚合属于每个键的所有属性应该很容易。

从您的预期输出来看,对于每个键,似乎只有一个<weapon_stat>元素具有stat_name='weapon_fire_count'。假设这是正确的,您可以通过迭代这些<weapon_stat>元素来轻松地获得所有item_id值:

<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)与当前节点(其是由上述for-each选择的节点)的@item_id@vehicle_id进行比较。

总而言之,您希望将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示例中,似乎不是每个键都有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> 

最新更新