为Access导入分组定义良好的扁平XML(XSLT 1.0)

时间:2012-07-24 06:27:28

标签: xml ms-access xslt grouping xslt-1.0

我的本​​地会计系统有一个输出,它由一个信封标签和一个重复的字段序列组成,但没有分组。我以前没有XSL的经验,但一直试图找到一个解决方案,并找到了适用于XSLT 2.0的解决方案。不幸的是,似乎Access 2007只接受XSLT 1.0转换。

你能帮我找一个有效的XSLT 1.0解决方案吗?

这是原始平面XML中的两个记录:

<ENVELOPE>
  <DBCFIXED>  <DBCDATE>1-Apr-2011</DBCDATE>
    <DBCPARTY></DBCPARTY>
  </DBCFIXED>
  <DBCVCHTYPE>Stock Journal</DBCVCHTYPE>
  <DBCVCHNO>1</DBCVCHNO>
  <DBCVCHREF></DBCVCHREF>
  <DBCSTNO></DBCSTNO>
  <DBCSERVICETAXNO></DBCSERVICETAXNO>
  <DBCPANNO></DBCPANNO>
  <DBCCSTNO></DBCCSTNO>
  <DBCNARR>Opening balance transfar</DBCNARR>
  <DBCQTY>0.000 Kg</DBCQTY>
  <DBCRATE></DBCRATE>
  <DBCAMOUNT></DBCAMOUNT>
  <DBCADDLCOST></DBCADDLCOST>
  <DBCGROSSAMT></DBCGROSSAMT>
  <DBCLEDAMT></DBCLEDAMT>
  <DBCFIXED>  <DBCDATE></DBCDATE>
    <DBCPARTY>ME KN YARN BL 1</DBCPARTY>
  </DBCFIXED>
  <DBCVCHTYPE></DBCVCHTYPE>
  <DBCVCHNO></DBCVCHNO>
  <DBCVCHREF></DBCVCHREF>
  <DBCSTNO></DBCSTNO>
  <DBCSERVICETAXNO></DBCSERVICETAXNO>
  <DBCPANNO></DBCPANNO>
  <DBCCSTNO></DBCCSTNO>
  <DBCNARR></DBCNARR>
  <DBCQTY>0.150 Kg</DBCQTY>
  <DBCRATE>566.00/Kg</DBCRATE>
  <DBCAMOUNT>-84.90</DBCAMOUNT>
  <DBCADDLCOST></DBCADDLCOST>
  <DBCGROSSAMT></DBCGROSSAMT>
  <DBCLEDAMT></DBCLEDAMT>
</ENVELOPE>

对于导入Access,我需要将数据分组到以DBCFIXED开头的记录中,直到下一个DBCFIXED。类似的东西:

<InventoryDaybook>
  <record>
    <DBCFIXED>  
      <DBCDATE>1-Apr-2011</DBCDATE>
      <DBCPARTY/>
    </DBCFIXED>
    <DBCVCHTYPE>Stock Journal</DBCVCHTYPE>
    <...></...>
  </record>
  <record>
    <...></...>
  </record>
/<InventoryDaybook>

有效的XSLT 2.0代码是

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
  <InventoryDaybook>
    <xsl:for-each-group select="*" group-starting-with="DBCFIXED">
      <record>
        <xsl:copy-of select="current-group()"/>
      </record>
    </xsl:for-each-group>
  </InventoryDaybook>
</xsl:template>
</xsl:stylesheet>

使用XSL可以做些什么是令人惊讶的,但我的知识似乎太少了......提前感谢您的帮助和理解。

2 个答案:

答案 0 :(得分:1)

祝贺蒂姆第一个正确的解决方案。虽然蒂姆是完全正确的,但我只是想引起OP的注意,有两种一般形式的解决方案,XSLT 1.0组 - 起始 - 一个头节点被排除在密钥之外(如Tim的情况),以及包含头节点的另一个(如下所示)。我不确定哪个优越。也许迪米特可以告诉我们。

因此,为了感兴趣,这里是替代形式,其中包括密钥中的头节点。

包含头节点的密钥形式

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="records" match="ENVELOPE/*" use="generate-id(
            (preceding-sibling::DBCFIXED|self::DBCFIXED)[last()])" />

   <xsl:template match="/ENVELOPE">
      <InventoryDaybook>
         <xsl:apply-templates select="DBCFIXED" mode="group-head" />
      </InventoryDaybook>
   </xsl:template>

   <xsl:template match="DBCFIXED" mode="group-head">
      <record>
         <xsl:apply-templates select="key('records', generate-id())" />
      </record>
   </xsl:template>

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

非常轻微的优势

  1. 密钥匹配条件更简单。
  2. 头节点模板中少一行。
  3. 头节点通过apply-templates而不是直接复制。如果你做的不仅仅是直接复制,这可能是有益的。
  4. 非常轻微的缺点

    1. 密钥使用属性更复杂
    2. 必须添加模式以区分对头节点进行分组和对其进行下游处理。尽管如此,这也是一个优势,因为模式设计者可以改进自我文档。

答案 1 :(得分:0)

这可以通过 xsl:key 在XSLT1.0中实现,它匹配非DBCFIXED元素,并使用前面的第一个DBCFIXED元素作为键

<xsl:key 
    name="records" 
    match="ENVELOPE/*[not(self::DBCFIXED)]" 
    use="generate-id(preceding-sibling::DBCFIXED[1])" />

然后,当您匹配单个 DBCFIXED 元素时,您可以轻松查找构成记录的关联元素

<xsl:apply-templates select="key('records', generate-id())" />

这是完整的XLST

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="records" match="ENVELOPE/*[not(self::DBCFIXED)]" use="generate-id(preceding-sibling::DBCFIXED[1])" />
   <xsl:template match="/ENVELOPE">
      <InventoryDaybook>
         <xsl:apply-templates select="DBCFIXED" />
      </InventoryDaybook>
   </xsl:template>

   <xsl:template match="DBCFIXED">
      <record>
         <xsl:copy-of select="." />
         <xsl:apply-templates select="key('records', generate-id())" />
      </record>
   </xsl:template>

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

当应用于输入XML时,输出以下内容

<InventoryDaybook>
   <record>
      <DBCFIXED>
         <DBCDATE>1-Apr-2011</DBCDATE>
         <DBCPARTY/>
      </DBCFIXED>
      <DBCVCHTYPE>Stock Journal</DBCVCHTYPE>
      <DBCVCHNO>1</DBCVCHNO>
      <DBCVCHREF/>
      <DBCSTNO/>
      <DBCSERVICETAXNO/>
      <DBCPANNO/>
      <DBCCSTNO/>
      <DBCNARR>Opening balance transfar</DBCNARR>
      <DBCQTY>0.000 Kg</DBCQTY>
      <DBCRATE/>
      <DBCAMOUNT/>
      <DBCADDLCOST/>
      <DBCGROSSAMT/>
      <DBCLEDAMT/>
   </record>
   <record>
      <DBCFIXED>
         <DBCDATE/>
         <DBCPARTY>ME KN YARN BL 1</DBCPARTY>
      </DBCFIXED>
      <DBCVCHTYPE/>
      <DBCVCHNO/>
      <DBCVCHREF/>
      <DBCSTNO/>
      <DBCSERVICETAXNO/>
      <DBCPANNO/>
      <DBCCSTNO/>
      <DBCNARR/>
      <DBCQTY>0.150 Kg</DBCQTY>
      <DBCRATE>566.00/Kg</DBCRATE>
      <DBCAMOUNT>-84.90</DBCAMOUNT>
      <DBCADDLCOST/>
      <DBCGROSSAMT/>
      <DBCLEDAMT/>
   </record>
</InventoryDaybook>