2

我正在尝试对来自 filemaker 数据库的记录进行分组。我正在导出为 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 文本不同,则应将其添加到另一个组中。

4

2 回答 2

4

如果您使用的是 XSLT 2.0,请查找有关xsl:for-each-group. 如果您使用的是 1.0,请查找有关“Muenchian 分组”的信息。

于 2013-11-04T00:48:59.887 回答
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元素(对于组中的所有元素都是相同的)。

试试这个(完整的)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_Typefm: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() &gt; 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标识转换来复制现有元素,而不是xsl:copy-of

于 2013-11-04T09:26:37.117 回答