我正在尝试从文件制作者数据库中对记录进行分组。我正在导出为XML,可以选择使用XSLT进行转换。
我一直在做一些搜索和阅读其他帖子,我认为它们不会涵盖我想要做的事情。
XML的摘录:
<?xml version="1.0" encoding="UTF-8"?>
<!-- This grammar has been deprecated - use FMPXMLRESULT instead -->
<FMPDSORESULT xmlns="http://www.filemaker.com/fmpdsoresult">
<ERRORCODE>0</ERRORCODE>
<DATABASE>Artpostersnbbs.fp7</DATABASE>
<LAYOUT />
<ROW MODID="19" RECORDID="11116">
<Art_Type>Poster</Art_Type>
<Location>1</Location>
<Line1>ELEVATOR
MACHINE
ROOM
107</Line1>
</ROW>
<ROW MODID="19" RECORDID="11116">
<Art_Type>Poster</Art_Type>
<Location>2</Location>
<Line1>ELEVATOR
MACHINE
ROOM
107</Line1>
</ROW>
<ROW MODID="19" RECORDID="11116">
<Art_Type>Poster</Art_Type>
<Location>3</Location>
<Line1>ELEVATOR
MACHINE
ROOM
107</Line1>
</ROW>
</FMPDSORESULT>
我希望该组的每条记录都与ART_TYPE和LINE1相匹配。在分组之后,它应该将匹配中的位置添加到正在分组的位置,因此它应该如下所示:
<ROW MODID="19" RECORDID="11116">
<Art_Type>Poster</Art_Type>
<Location>1 2 3</Location>
<Line1>ELEVATOR
MACHINE
ROOM
107
</Line1>
</ROW>
如何开始的任何帮助将不胜感激。还有什么好的xslt 1.0测试程序吗?
提前致谢!
编辑:我被指向muenchian分组并找到了这个网站:http://www.jenitennison.com/xslt/grouping/muenchian.html
所以从阅读中得出结论:
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="artTypeNames" match="ROW" use="Art_Type" />
<xsl:key name="artCopy" match="ROW" use="Line1" />
<xsl:template match="FMPDSORESULT">
<xsl:for-each select="ROW[count(. | key('artTypeNames', Art_Type)[1]) = 1]">
<xsl:sort select="Art_Type" />
<xsl:value-of select="Art_Type" />
<xsl:for-each select="key('artTypeNames', Art_Type)">
<xsl:sort select="Art_Type" />
<xsl:value-of select="Art_Type" />
</xsl:for-each>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
我将XML和XSLT输入到在线XML Transformer中,我得到'XSLT无效'错误。
这令人沮丧。
EDIT2:在Tim的帮助下,我能够构建一个合适的XSLT转换:
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fm="http://www.filemaker.com/fmpdsoresult">
<xsl:template match="fm:FMPDSORESULT">
<xsl:apply-templates select="fm:ROW[count(. | key('lineData', fm:Line1)[1]) = 1]">
</xsl:apply-templates>
</xsl:template>
<xsl:template match="fm:ROW">
<xsl:copy>
<xsl:apply-templates select="fm:Art_Type" />
<fm:Location>
<xsl:apply-templates select="key('artTypeNames', fm:Art_Type)/fm:Location" />
</fm:Location>
<xsl:apply-templates select="fm:Line1" />
</xsl:copy>
</xsl:template>
<xsl:template match="fm:Location">
<xsl:if test="position() > 1">-</xsl:if>
<xsl:value-of select="." />
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
它将Art_Type分组,然后按Line1文本分组,但现在将位置编号添加到所有这些中,如下所示:
<ROW xmlns="http://www.filemaker.com/fmpdsoresult">
<Art_Type>Poster</Art_Type>
<fm:Location xmlns:fm="http://www.filemaker.com/fmpdsoresult" xmlns="">1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34</fm:Location>
<Line1>CUSTODIAL
LOUNGE
117A
</Line1>
</ROW>
<ROW xmlns="http://www.filemaker.com/fmpdsoresult">
<Art_Type>Poster</Art_Type>
<fm:Location xmlns:fm="http://www.filemaker.com/fmpdsoresult" xmlns="">1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34</fm:Location>
<Line1>STORAGE
ROOM
117B
</Line1>
</ROW>
如果Line1文本不同,则应将其添加到另一个组中。
答案 0 :(得分:4)
如果您使用的是XSLT 2.0,请查找有关xsl:for-each-group
的信息。如果您使用的是1.0,请查找有关“Muenchian分组”的信息。
答案 1 :(得分:3)
评论中提到的一个问题是名称空间。在XML中,有一个名称空间声明:
<FMPDSORESULT xmlns="http://www.filemaker.com/fmpdsoresult">
这意味着元素及其下面的所有后代元素都属于该命名空间(除非过度下载)。但是在你的XSLT中没有提到任何命名空间,因此XSLT正在寻找属于NO命名空间的元素。
您需要在XSLT中声明命名空间,然后确保在尝试引用原始XML中的任何元素时使用命名空间前缀。
<xsl:stylesheet version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fm="http://www.filemaker.com/fmpdsoresult">
<xsl:key name="artTypeNames" match="fm:ROW" use="fm:Art_Type" />
<xsl:template match="fm:FMPDSORESULT">
至于你的XSLT示例,我在尝试时没有收到任何错误,尽管你可能只是展示了一个片段。分组看起来是正确的(假设您确实打算通过 Art_Type 对 ROW 元素进行分组),但您缺少的是复制现有元素的任何代码。
<xsl:for-each select="fm:ROW[count(. | key('artTypeNames', fm:Art_Type)[1]) = 1]">
<xsl:sort select="fm:Art_Type" />
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:copy-of select="fm:Art_Type" />
因此,此代码段会复制现有的 ROW 元素及其属性,然后复制 Art_Type 元素(对于组中的所有元素都是相同的)。< / p>
试试这个(完整的)XSLT
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fm="http://www.filemaker.com/fmpdsoresult">
<xsl:key name="artTypeNames" match="fm:ROW" use="fm:Art_Type" />
<xsl:template match="fm:FMPDSORESULT">
<xsl:for-each select="fm:ROW[count(. | key('artTypeNames', fm:Art_Type)[1]) = 1]">
<xsl:sort select="fm:Art_Type" />
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:copy-of select="fm:Art_Type" />
<fm:Location>
<xsl:for-each select="key('artTypeNames', fm:Art_Type)">
<xsl:if test="position() > 1">-</xsl:if>
<xsl:value-of select="fm:Location" />
</xsl:for-each>
</fm:Location>
<xsl:copy-of select="fm:Line1" />
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
请注意,内部for-each循环中不需要排序,因为显然 Art_Type 对于组中的所有元素都是相同的。
编辑:如果要检查两个字段以确定组成一个组,则需要使用连接键来实现此目的。在您的情况下,您说要同时检查 Art_Type 和 fm:Line1 ,因此您的密钥可能看起来像这样。
<xsl:key name="artTypeNames" match="fm:ROW" use="concat(fm:Art_Type, '||', fm:Line1)" />
注意使用'||'这里。这可以是任何东西,只要它没有出现在你正在检查的任何一个元素中。
要使用此密钥,您只需使用与之前类似的方式,但使用元素的连接值。例如
<xsl:apply-templates select="fm:ROW[count(. | key('artTypeNames', concat(fm:Art_Type, '||', fm:Line1))[1]) = 1]">
注意,通常最好使用 xsl:apply-templates 而不是 xsl:for-each ,如果只是为了减少缩进。
尝试这个XSLT
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fm="http://www.filemaker.com/fmpdsoresult">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="artTypeNames" match="fm:ROW" use="concat(fm:Art_Type, '||', fm:Line1)"/>
<xsl:template match="fm:FMPDSORESULT">
<xsl:apply-templates select="fm:ROW[count(. | key('artTypeNames', concat(fm:Art_Type, '||', fm:Line1))[1]) = 1]">
<xsl:sort select="fm:Art_Type"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="fm:ROW">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="fm:Art_Type"/>
<fm:Location>
<xsl:apply-templates select="key('artTypeNames', concat(fm:Art_Type, '||', fm:Line1))/fm:Location"/>
</fm:Location>
<xsl:apply-templates select="fm:Line1"/>
</xsl:copy>
</xsl:template>
<xsl:template match="fm:Location">
<xsl:if test="position() > 1">-</xsl:if>
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
另请注意使用XSLT identity transform复制现有元素而不是 xsl:copy-of