我正在使用XSLT转换来生成XML文档,该文档在创建后将被拆分以生成多个文件。最终文件的一般结构如下:
<DOC>
<NEWFILE/>
<REALROOT>
<SENDER></SENDER>
<INVOICE>
<IVC_ID></IVS_ID>
<LINEITEM></LINEITEM>
<LINEITEM></LINEITEM>
...
</INVOICE>
<INVOICE>
<IVC_ID></IVS_ID>
<LINEITEM></LINEITEM>
<LINEITEM></LINEITEM>
...
</INVOICE>
...
</REALROOT>
<NEWFILE/>
<REALROOT>
<SENDER></SENDER>
<INVOICE>
<IVC_ID></IVS_ID>
<LINEITEM></LINEITEM>
<LINEITEM></LINEITEM>
...
</INVOICE>
<INVOICE>
<IVC_ID></IVS_ID>
<LINEITEM></LINEITEM>
<LINEITEM></LINEITEM>
...
</INVOICE>
...
</REALROOT>
<NEWFILE/>
</DOC>
DOC
和<NEWFILE/>
标签是最终产品的边界,但这不是问题的主题。
在输出到上述结构之前,我的输入数据需要按发件人和发票分组,我已设法做到这一点,但我还想限制每个文件的发票数量而无法找到一种方法。
我的输入数据会细分为订单项级别,如下所示:
<ROOT>
<DATA>
<SNDR>1</SNDR>
<INVOICE>1</INVOICE>
<LINEITEM>1</LINEITEM>
</DATA>
<DATA>
<SNDR>1</SNDR>
<INVOICE>1</INVOICE>
<LINEITEM>2</LINEITEM>
</DATA>
<DATA>
<SNDR>1</SNDR>
<INVOICE>2</INVOICE>
<LINEITEM>1</LINEITEM>
</DATA>
<DATA>
<SNDR>1</SNDR>
<INVOICE>3</INVOICE>
<LINEITEM>1</LINEITEM>
</DATA>
<DATA>
<SNDR>1</SNDR>
<INVOICE>3</INVOICE>
<LINEITEM>2</LINEITEM>
</DATA>
<DATA>
<SNDR>2</SNDR>
<INVOICE>1</INVOICE>
<LINEITEM>1</LINEITEM>
</DATA>
<DATA>
<SNDR>2</SNDR>
<INVOICE>2</INVOICE>
<LINEITEM>1</LINEITEM>
</DATA>
</ROOT>
如果我将每个文件限制为2个发票,我希望这个输出:
<DOC>
<REALROOT>
<SENDER>1</SENDER>
<INVOICE>
<IVC_ID>1</IVS_ID>
<LINEITEM>1</LINEITEM>
<LINEITEM>2</LINEITEM>
</INVOICE>
<INVOICE>
<IVC_ID>2</IVS_ID>
<LINEITEM>1</LINEITEM>
</INVOICE>
</REALROOT>
<NEWFILE/>
<REALROOT>
<SENDER>1</SENDER>
<INVOICE>
<IVC_ID>3</IVS_ID>
<LINEITEM>1</LINEITEM>
<LINEITEM>2</LINEITEM>
</INVOICE>
</REALROOT>
<NEWFILE/>
<REALROOT>
<SENDER>2</SENDER>
<INVOICE>
<IVC_ID>1</IVS_ID>
<LINEITEM>1</LINEITEM>
</INVOICE>
<INVOICE>
<IVC_ID>2</IVS_ID>
<LINEITEM>1</LINEITEM>
</INVOICE>
</REALROOT>
</DOC>
这是我的目标。这允许我按发件人和发票对行进行分组,但我无法弄清楚如何处理发票数量限制。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="data-by-SNDR" match="/ROOT/DATA" use="SNDR"/>
<xsl:key name="data-by-invoice" match="/ROOT/DATA" use="concat(SNDR, INVOICE)"/>
<xsl:template match="/ROOT">
<DOC>
<newFile/>
<xsl:for-each select="DATA[not(SNDR = preceding-sibling::DATA[1]/SNDR)]">
<REALROOT>
<SNDR>
<xsl:value-of select="SNDR"/>
</SNDR>
<xsl:for-each select="key('data-by-SNDR', current()/SNDR)[not(INVOICE = preceding-sibling::DATA[1]/INVOICE)]">
<INVOICE>
<IVC_ID>
<xsl:value-of select="INVOICE"/>
</IVC_ID>
<xsl:for-each select="key('data-by-invoice',concat(current()/SNDR, current()/INVOICE))">
<LINEITEM>
<xsl:value-of select="LINEITEM"/>
</LINEITEM>
</xsl:for-each>
</INVOICE>
</xsl:for-each>
</REALROOT>
<newFile/>
</xsl:for-each>
</DOC>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:0)
首先,对于每个发件人,您需要一份此发件人的所有发票清单。
这已经是你在前两个foreach所做的事了,但我说你需要一个清单。所以第二个,不需要是一个foreach。把它们放在一个变量中:
<xsl:variable name="invoicesWithThisSender"
select="key('data-by-SNDR', current()/SNDR)[not(INVOICE = preceding-sibling::DATA[1]/INVOICE)]" />
它是一个变量,而不是for-each。
现在你需要在尽可能多的文件中写下这个列表的所有元素。
由于XSLT 1.0不提供分区机制,我知道这样做的唯一方法是调用递归命名模板。
试试这个:
<xsl:template name="writeFilesForSender">
<xsl:param name="invoicesWithThisSender" />
<xsl:if test="$invoicesWithThisSender">
<NEWFILE />
<REALROOT>
<SNDR>
<xsl:value-of select="SNDR" />
</SNDR>
<xsl:for-each select="$invoicesWithThisSender[position() <= 2]">
<INVOICE>
<IVC_ID>
<xsl:value-of select="INVOICE" />
</IVC_ID>
</INVOICE>
</xsl:for-each>
</REALROOT>
<xsl:call-template name="writeFilesForSender">
<xsl:with-param name="invoicesWithThisSender"
select="$invoicesWithThisSender[position() > 2]" />
</xsl:call-template>
</xsl:if>
</xsl:template>
用它来称呼它:
<xsl:call-template name="writeFilesForSender">
<xsl:with-param name="invoicesWithThisSender"
select="$invoicesWithThisSender" />
</xsl:call-template>
根据我的理解和测试,你的问题就解决了。