XSLT для генерации последовательных номеров, которые могут быть сброшены - PullRequest
1 голос
/ 08 июля 2011
<?xml version="1.0" encoding="UTF-8" ?>
<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
    <ERRORCODE>0</ERRORCODE>
    <PRODUCT BUILD="01-25-2011" NAME="FileMaker" VERSION="Pro 11.0v3"/>
    <DATABASE DATEFORMAT="M/d/yyyy" LAYOUT="Export to Ledes" NAME="StateFarmLedes1998b.fp7" RECORDS="27" TIMEFORMAT="h:mm:ss a"/>
    <METADATA>
        <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="date of bill" TYPE="DATE"/>
        <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="Invoice #" TYPE="NUMBER"/>
        <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="Company Name" TYPE="TEXT"/>
    </METADATA>
    <RESULTSET FOUND="25">
        <ROW MODID="25" RECORDID="54">
            <COL>
                <DATA>20110707</DATA>
            </COL>
            <COL>
                <DATA>2949801</DATA>
            </COL>
            <COL>
                <DATA>Foo</DATA>
            </COL>
        </ROW>
        <ROW MODID="25" RECORDID="54">
            <COL>
                <DATA>20110707</DATA>
            </COL>
            <COL>
                <DATA>2949802</DATA>
            </COL>
            <COL>
                <DATA>Bar</DATA>
            </COL>
        </ROW>
    </RESULTSET>
</FMPXMLRESULT>

Для вышеприведенного XML, как бы вы написали XSLT-преобразование, которое генерирует вывод с разделителями по каналам, с последовательным подсчетом "отдельной позиции" для каждой позиции?Счетчик позиций должен сбрасываться в 1 каждый раз, когда меняется номер счета.

1 Ответ

2 голосов
/ 08 июля 2011

Это преобразование XSLT 2.0 :

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:x="http://www.filemaker.com/fmpxmlresult">

 <xsl:output method="text"/>

 <xsl:template match="/">
  <xsl:for-each-group select="/*/x:RESULTSET/x:ROW"
   group-adjacent="x:COL[2]/x:DATA">
    <xsl:apply-templates select="current-group()"/>
   </xsl:for-each-group>
 </xsl:template>

 <xsl:template match="x:ROW">
  <xsl:text>&#xA;</xsl:text>
  <xsl:sequence select=
  "string-join((xs:string(position()), x:COL/x:DATA), ',')"/>
 </xsl:template>
</xsl:stylesheet>

применительно к этому XML-документу (по сути предоставленный, но добавил еще одну строку, чтобы сделать его интересным):

<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
    <ERRORCODE>0</ERRORCODE>
    <PRODUCT BUILD="01-25-2011" NAME="FileMaker" VERSION="Pro 11.0v3"/>
    <DATABASE DATEFORMAT="M/d/yyyy" LAYOUT="Export to Ledes" NAME="StateFarmLedes1998b.fp7" RECORDS="27" TIMEFORMAT="h:mm:ss a"/>
    <METADATA>
        <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="date of bill" TYPE="DATE"/>
        <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="Invoice #" TYPE="NUMBER"/>
        <FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="Company Name" TYPE="TEXT"/>
    </METADATA>
    <RESULTSET FOUND="25">
        <ROW MODID="25" RECORDID="54">
            <COL>
                <DATA>20110707</DATA>
            </COL>
            <COL>
                <DATA>2949801</DATA>
            </COL>
            <COL>
                <DATA>Foo</DATA>
            </COL>
        </ROW>
        <ROW MODID="25" RECORDID="54">
            <COL>
                <DATA>20110707</DATA>
            </COL>
            <COL>
                <DATA>2949801</DATA>
            </COL>
            <COL>
                <DATA>Foo</DATA>
            </COL>
        </ROW>
        <ROW MODID="25" RECORDID="54">
            <COL>
                <DATA>20110707</DATA>
            </COL>
            <COL>
                <DATA>2949802</DATA>
            </COL>
            <COL>
                <DATA>Bar</DATA>
            </COL>
        </ROW>
    </RESULTSET>
</FMPXMLRESULT>

дает требуемый, правильный результат :

1,20110707,2949801,Foo
2,20110707,2949801,Foo
1,20110707,2949802,Bar

Объяснение :

Использование <xsl:for-each-group> с атрибутом group-adjacent.

II.Решение XSLT 1.0 :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:x="http://www.filemaker.com/fmpxmlresult"
 >
 <xsl:output method="text"/>

 <xsl:key name="kFollowing"
      match="x:ROW"
      use="generate-id(
            preceding-sibling::x:ROW
              [x:COL[2]/x:DATA
              =
               current()/x:COL[2]/x:DATA
              and
               not(preceding-sibling::x:ROW/x:COL[2]/x:DATA
                  =
                   current()/x:COL[2]/x:DATA
                  )
               ]
               [1]
                        )"
 />

 <xsl:template match=
  "x:ROW[not(x:COL[2]/x:DATA
            =
            preceding-sibling::x:ROW/x:COL[2]/x:DATA
            )
        ]
  ">
  <xsl:apply-templates mode="group"
       select=".|key('kFollowing',generate-id())"/>
 </xsl:template>

 <xsl:template match="x:ROW" mode="group">
  <xsl:value-of select=
   "concat('&#xA;',position())"/>

  <xsl:for-each select="x:COL/x:DATA">
   <xsl:value-of select="concat(',',.)"/>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

Когда это преобразование применяется к тому же XML-документу (показан выше), получается тот же правильный результат:

1,20110707,2949801,Foo
2,20110707,2949801,Foo
1,20110707,2949802,Bar

Объяснение :

  1. Мы используем шаблон, который соответствует каждому элементу "head of group" x:ROW.

  2. Мы указали ключ, который индексирует любой x:ROW в группе с помощью generate-id() "главы группы".Это удобно для простого указания всей группы и применения шаблонов к ее элементам (в режиме «группа»).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...