我正在尝试将会计系统的XML输出转换为可以导入Access的XML。不幸的是,Access只接受XSL1.0进行转换,所以我已经请求帮助将XSL2.0解决方案转换为在XSL1.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(XSLT1.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包装标记中,这些标记表示"sub"行"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?这个解决方案中有类似的内容吗?双重转换问题的解决方案
我意识到我在论坛上就同一个更大的问题问了两次,但我真的很感谢你在这方面的帮助。
您当然可以使用单页管道解决方案。这里是一个使用两个分组键的非管道解决方案。
<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>