【问题标题】:Grouping of a well defined flat XML for Access import (XSLT 1.0)为 Access 导入 (XSLT 1.0) 对定义明确的平面 XML 进行分组
【发布时间】:2012-07-22 10:36:17
【问题描述】:

我有一个来自我们本地会计系统的输出,它由一个信封标签和一个重复的字段序列组成,但没有分组。我以前没有 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 可以完成的事情令人惊叹,但我的知识似乎太少了。在此先感谢您的帮助和理解。

【问题讨论】:

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


    【解决方案1】:

    这可以在 XSLT1.0 中通过 xsl:key 来实现,它匹配非 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>
    

    【讨论】:

    • 非常感谢蒂姆的快速回复,这就像一个魅力!
    【解决方案2】:

    祝贺蒂姆第一个正确的解决方案。虽然 Tim 是绝对正确的,但我只是想提请 OP 的注意,XSLT 1.0 group-starting-with 有两种通用形式的解决方案 - 一种是头节点从密钥中排除(如 Tim 的情况),另一个包含头节点(如下所示)。我不确定哪个更好。也许 Dimitre 可以告诉我们。

    所以为了感兴趣,这里是另一种形式,其中包括键中的头节点。

    Head-node-included-in-key 形式

    <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. 头节点通过应用模板而不是直接复制。如果您做的不仅仅是直接复制,这可能会有所帮助。

    非常轻微的缺点

    1. 键使用属性更复杂
    2. 必须添加模式来区分头节点分组和它的下游处理。虽然在方式上,这也是一个优势,因为模式指示符改进了自我记录。

    【讨论】:

    • 嗨,肖恩,感谢您提供替代解决方案。非常感谢其他方法!但是,由于某种原因,由于 Access 中的无限递归,它会产生溢出错误。在xslttest.appspot.com 上也一样,它会返回一个循环警告。
    • 再次感谢肖恩。看到这两种方式非常有趣。我绝对需要看看这些模式如何与应用模板一起工作。而且我认为这对于有类似问题的其他海报进行比较也可能非常有趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 2023-02-10
    • 1970-01-01
    相关资源
    最近更新 更多