0

我正在尝试将我们会计系统的 XML 输出转换为可以导入 Access 的 XML。不幸的是,Access 只接受 XSL 1.0 进行转换,所以我已经请求帮助将 XSL 2.0 解决方案转换为在 XSL 1.0 下工作的东西。(分组问题)。那里的解决方案非常适合我认为我需要的 Access 导入。

Access 导入现在可以工作,但我意识到数据的形式仍然不能真正使用。数据由标题行和子行组成,其中不填充标题数据。但是为了有意义地聚合,需要填充数据。

这是导入到 Access 中的当前 XML 的样子:

DBCDATE     |DBBCPARTY         |DBCVCHTYPE     |DBCVCHNO   |DBCVCHREF    
1-Apr-2011  |                  |Stock Journal  |1          |             
            |ME KN YARN B      |               |           |             
            |ME KN YARN G      |               |           |             
            |ME KN YARN I      |               |           |             
3-Apr-2011  |                  |Stock Journal  |2          |903          
            |TIB Raw Wool      |               |           |             
            |ME KN YARN D      |               |           |             

标题行中的字段也需要复制到子行中:DBCDATE、DBCVCHTYPE、DBCVCHNO、DBCVCHREF、DBCNARR

我可以使用 Access 中的一些 VBA 编程来做到这一点,甚至可以将数据导出到 Excel 并应用一些公式,但是数据非常大,我们正在研究提取更多数据。而且它的灵活性会降低。此外,问题可能涉及对已分组的 XML 进行更多分组的方向(现在它以 InventoryDaybook 标记结构的形式分组为可导入的行。

所以这是原始的 XML:编辑:增强的 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>
  <DBCFIXED>  <DBCDATE>1-Apr-2011</DBCDATE>
    <DBCPARTY></DBCPARTY>
  </DBCFIXED>
  <DBCVCHTYPE>Stock Journal</DBCVCHTYPE>
  <DBCVCHNO>2</DBCVCHNO>
  <DBCVCHREF>903</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.260 Kg</DBCQTY>
  <DBCRATE>26.00/Kg</DBCRATE>
  <DBCAMOUNT>-8.70</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.360 Kg</DBCQTY>
  <DBCRATE>21.00/Kg</DBCRATE>
  <DBCAMOUNT>-45.80</DBCAMOUNT>
  <DBCADDLCOST></DBCADDLCOST>
  <DBCGROSSAMT></DBCGROSSAMT>
  <DBCLEDAMT></DBCLEDAMT>
</ENVELOPE>

这是 XSL (XSLT 1.0),与解决方案略有不同:

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

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

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

编辑:提供生成的 XML(感谢 Martin 指出缺少的生成 XML)

这就是 XML 最终的样子: InventoryDaybook 包装标签已进一步区分为一个“标题”标签,其中包含有关日期、凭证类型、凭证编号、凭证参考和叙述的信息。需要将这些字段 DBCDATE、DBCVCHTYPE、DBCVCHNO、DBCVCHREF、DBCNARR 复制到其他 InventoryDaybook 包装标签,这些标签代表“子”行。'Headers' 可以由 DBCDATE 识别 - 此字段仅为标题行设置。

<Data>
   <InventoryDaybook name="header">
      <DBCDATE>1-Apr-2011</DBCDATE>
      <DBCPARTY/>
      <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/>
   </InventoryDaybook>
   <InventoryDaybook name="sub">
      <DBCDATE>1-Apr-2011</DBCDATE>
      <DBCPARTY>ME KN YARN BL 1</DBCPARTY>
      <DBCVCHTYPE>Stock Journal</DBCVCHTYPE>
      <DBCVCHNO>1</DBCVCHNO>
      <DBCVCHREF/>
      <DBCSTNO/>
      <DBCSERVICETAXNO/>
      <DBCPANNO/>
      <DBCCSTNO/>
      <DBCNARR>Opening balance transfar</DBCNARR>
      <DBCQTY>0.150 Kg</DBCQTY>
      <DBCRATE>566.00/Kg</DBCRATE>
      <DBCAMOUNT>-84.90</DBCAMOUNT>
      <DBCADDLCOST/>
      <DBCGROSSAMT/>
      <DBCLEDAMT/>
   </InventoryDaybook>
   <InventoryDaybook name="header">
      <DBCDATE>1-Apr-2011</DBCDATE>
      <DBCPARTY/>
      <DBCVCHTYPE>Stock Journal</DBCVCHTYPE>
      <DBCVCHNO>2</DBCVCHNO>
      <DBCVCHREF>903</DBCVCHREF>
      <DBCSTNO/>
      <DBCSERVICETAXNO/>
      <DBCPANNO/>
      <DBCCSTNO/>
      <DBCNARR>Opening balance transfar</DBCNARR>
      <DBCQTY>0.000 Kg</DBCQTY>
      <DBCRATE/>
      <DBCAMOUNT/>
      <DBCADDLCOST/>
      <DBCGROSSAMT/>
      <DBCLEDAMT/>
   </InventoryDaybook>
   <InventoryDaybook name="sub">
      <DBCDATE>1-Apr-2011</DBCDATE>
      <DBCPARTY>ME KN YARN BL 1</DBCPARTY>
      <DBCVCHTYPE>Stock Journal</DBCVCHTYPE>
      <DBCVCHNO>2</DBCVCHNO>
      <DBCVCHREF>903</DBCVCHREF>
      <DBCSTNO/>
      <DBCSERVICETAXNO/>
      <DBCPANNO/>
      <DBCCSTNO/>
      <DBCNARR>Opening balance transfar</DBCNARR>
      <DBCQTY>0.260 Kg</DBCQTY>
      <DBCRATE>26.00/Kg</DBCRATE>
      <DBCAMOUNT>-8.70</DBCAMOUNT>
      <DBCADDLCOST/>
      <DBCGROSSAMT/>
      <DBCLEDAMT/>
   </InventoryDaybook>
   <InventoryDaybook name="sub">
      <DBCDATE>1-Apr-2011</DBCDATE>
      <DBCPARTY>ME KN YARN BL 1</DBCPARTY>
      <DBCVCHTYPE>Stock Journal</DBCVCHTYPE>
      <DBCVCHNO>2</DBCVCHNO>
      <DBCVCHREF>903</DBCVCHREF>
      <DBCSTNO/>
      <DBCSERVICETAXNO/>
      <DBCPANNO/>
      <DBCCSTNO/>
      <DBCNARR>Opening balance transfar</DBCNARR>
      <DBCQTY>0.360 Kg</DBCQTY>
      <DBCRATE>21.00/Kg</DBCRATE>
      <DBCAMOUNT>-45.80</DBCAMOUNT>
      <DBCADDLCOST/>
      <DBCGROSSAMT/>
      <DBCLEDAMT/>
   </InventoryDaybook>
</Data>

有没有办法在 XSL 中做到这一点?我还想知道这是否意味着再次转换返回的 XML?这个解决方案中的东西?双变换题的解法

我意识到我在论坛上问了两次同样的大问题,但我真的很感谢你在这方面的帮助。

4

1 回答 1

0

您当然可以使用单页管道解决方案。这是一个使用两个分组键的非管道解决方案。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />  

   <xsl:key name="header" match="ENVELOPE/*" use="generate-id(
  (preceding-sibling::DBCFIXED[DBCDATE != '']|self::DBCFIXED[DBCDATE != ''])[last()])" />
   <!-- The header key groups all the nodes belonging to a DBCDATE. This is
        a big group containing a number of 'sub' subgroups. -->

   <xsl:key name="sub" match="ENVELOPE/*" use="generate-id(
  (preceding-sibling::DBCFIXED|self::DBCFIXED)[last()])" />
   <!-- The sub key groups all the nodes under a DBCFIXED. This corresponds to
        one row in Access -->

   <xsl:template match="/*">
    <!-- This is our entry template. We gather up all the big header groups,
         and process them one group at a time in 'header' mode. -->  
      <Data>
         <xsl:apply-templates select="DBCFIXED[DBCDATE != '']" mode="header" />
      </Data>
   </xsl:template>

   <xsl:template match="DBCFIXED" mode="header">
    <!-- In this template we process the header group. -->
      <InventoryDaybook name="header">
         <!-- The first sub-group of the header group is to be marked as
              @name="header". Process the header subgroup -->
         <xsl:apply-templates select="key('sub', generate-id())" />
      </InventoryDaybook>
      <!-- Now process the other subgroups. These will be marked @name="sub". --> 
      <xsl:apply-templates select="
        key('header', generate-id()) /
        self::DBCFIXED[DBCDATE = '']"
        mode="sub" />
   </xsl:template>

   <xsl:template match="DBCFIXED" mode="sub">
      <!-- Processing a "sub" subgroup. -->
      <InventoryDaybook name="sub">
         <xsl:apply-templates select="key('sub', generate-id())" />
         <!-- The above selects the members of the subgroup. -->
      </InventoryDaybook>
   </xsl:template>

  <xsl:template match="ENVELOPE/*
    [not(self::DBCFIXED)]
    [preceding-sibling::DBCFIXED[1][DBCDATE = '']]
    [.='']">
  <!-- When we are processing a normal node in a 'sub' subgroup AND
       it doesn't have a value, pick up the default value from
       the related 'header' subgroup. This rule doesn't work for
       the DBCFIXED node. We need a special template for that. -->
      <xsl:copy>
        <xsl:value-of select="
        key('sub', generate-id(
        preceding-sibling::DBCFIXED[DBCDATE != ''][1]))        
        [local-name()=local-name(current())][1] " />
      </xsl:copy>
   </xsl:template>

   <xsl:template match="DBCFIXED">
      <!-- Flatten out the DBCFIXED node. -->
      <xsl:apply-templates select="@*|node()"/>
   </xsl:template>

   <xsl:template match="DBCDATE[ . = '']">
     <!-- Pick-up the default date from the parent DBCDATE. -->
      <xsl:copy>
        <xsl:value-of select="
        ../preceding-sibling::DBCFIXED/
        DBCDATE[ . != ''][1]" />        
      </xsl:copy>
   </xsl:template>

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

</xsl:stylesheet>
于 2012-07-25T07:59:56.510 回答