XML 使用 XSLT(复杂位置逻辑)到固定长度文件
XML to Fixed Length File Using XSLT (Complex Position Logic)
我们有一个需求需要将XML转换成定长文件。
第一条记录为 header,之后我们有实际记录。从第 2 条记录开始,我们需要应用下面提到的逻辑:
1.After 长度 45,考虑 10 个数字 0000001000,无论是什么
我们需要按照以下步骤检查和替换最后一位数字
table:
"For Positive Amount: (0000001000) - (000000100{)
{= 0
A = 1
B = 2
c = 3
D = 4
E = 5
F = 6
G = 7
H = 8
I = 9
我没有那么多想法,所以创建了小型 XSLT,请求任何人提供相同的帮助。
输入:
<?xml version='1.0' encoding='utf-8'?>
<ZR>
<INPUT>
<I_FIL>ERES</I_FIL>
</INPUT>
<TABLES>
<T_ER>
<item>
<DATA> HEADER1111111122222222333333344456</DATA>
</item>
<item>
<DATA>778944 D4E2 EA 1234567891 2018-11-060000001000EA
0000000000000100001020D04YA30TRE0000000XXXYYY 300{ P 2018-11-05</DATA>
</item>
<item>
<DATA>987654 D4E2 EA 1987654321 2018-11-060000002001EA
0000000000000100001020D04YA30UUU0000000XXXLRB 100{ P 2018-11-05</DATA>
</item>
.
.
.
.
.
.
.
.
</T_ER>
</TABLES>
</ZR>
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions" >
<xsl:output omit-xml-declaration="yes"/>
<xsl:param name="break" select="'
'" />
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA"/>
<xsl:value-of select="$break" />
</xsl:template>
</xsl:stylesheet>
预期输出:
HEADER1111111122222222333333344456
778944 D4E2 EA 1234567891 2018-11-06000000100{EA
0000000000000100001020D04YA30TRE0000000XXXYYY 300{ P 2018-11-05
987654 D4E2 EA 1987654321 2018-11-06000000200AEA
0000000000000100001020D04YA30UUU0000000XXXLRB 100{ P 2018-11-05
.
.
.
.
好吧,根据您的规范使用函数 string-length
、substring
和 translate
可以实现为:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output omit-xml-declaration="yes" />
<xsl:param name="break" select="'
'" />
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA" />
<xsl:value-of select="$break" />
<xsl:for-each select="ZR/TABLES/T_ER/item[position() != 1]">
<xsl:variable name="length" select="string-length(substring(DATA,0,46))" />
<xsl:variable name="tenNumbers" select="substring(DATA, ($length + 1), 10)"/>
<xsl:variable name="charToReplace" select="translate(substring($tenNumbers, string-length($tenNumbers), 1),'0123456789','{ABCDEFGHI')" />
<xsl:value-of select="concat(substring(DATA,0,46), substring(DATA, ($length + 1), 9), $charToReplace, substring(DATA,($length+11),(string-length(DATA) + 1)))"/>
<xsl:value-of select="$break" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
看起来你只是想根据你的地图替换第 55 个字符,所以你可以这样做...
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA"/>
<xsl:value-of select="$break" />
<xsl:for-each select="ZR/TABLES/T_ER/item[position() > 1]/DATA">
<xsl:variable name="char" select="substring('{ABCDEFGHI', number(substring(., 55, 1)) + 1, 1)" />
<xsl:value-of select="concat(substring(., 1, 54), $char, substring(., 56))" />
<xsl:value-of select="$break" />
</xsl:for-each>
</xsl:template>
这适用于 XSLT 1.0。
XSLT 2.0 解决方案可能是这样...
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA,
ZR/TABLES/T_ER/item[position() > 1]/DATA/concat(substring(., 1, 54), substring('{ABCDEFGHI', number(substring(., 55, 1)) + 1, 1), substring(., 56))"
separator="
" />
</xsl:template>
在 XSLT 3.0 中,您可以使用 map
,如果您想考虑两个或更多字符,则可以轻松扩展:
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:fn="http://www.w3.org/2005/xpath-functions" >
<xsl:output omit-xml-declaration="yes"/>
<xsl:param name="break" select="'
'" />
<xsl:variable name="chars" as="map(xs:string, xs:string)">
<xsl:map>
<xsl:map-entry key="'0'" select="'{'"/>
<xsl:map-entry key="'1'" select="'A'"/>
<xsl:map-entry key="'2'" select="'B'"/>
<xsl:map-entry key="'3'" select="'C'"/>
<xsl:map-entry key="'4'" select="'D'"/>
<xsl:map-entry key="'5'" select="'E'"/>
<xsl:map-entry key="'6'" select="'F'"/>
<xsl:map-entry key="'7'" select="'G'"/>
<xsl:map-entry key="'8'" select="'H'"/>
<xsl:map-entry key="'9'" select="'I'"/>
</xsl:map>
</xsl:variable>
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA,
ZR/TABLES/T_ER/item[position() > 1]/DATA/concat(substring(., 1, 54), $chars(substring(., 55, 1)), substring(., 56))" separator="
" />
</xsl:template>
</xsl:stylesheet>
XSLT 3.0 中可能有更好的方法,所以希望 Martin Honnen 很快就会说....
我们有一个需求需要将XML转换成定长文件。
第一条记录为 header,之后我们有实际记录。从第 2 条记录开始,我们需要应用下面提到的逻辑:
1.After 长度 45,考虑 10 个数字 0000001000,无论是什么
我们需要按照以下步骤检查和替换最后一位数字
table:
"For Positive Amount: (0000001000) - (000000100{)
{= 0
A = 1
B = 2
c = 3
D = 4
E = 5
F = 6
G = 7
H = 8
I = 9
我没有那么多想法,所以创建了小型 XSLT,请求任何人提供相同的帮助。
输入:
<?xml version='1.0' encoding='utf-8'?>
<ZR>
<INPUT>
<I_FIL>ERES</I_FIL>
</INPUT>
<TABLES>
<T_ER>
<item>
<DATA> HEADER1111111122222222333333344456</DATA>
</item>
<item>
<DATA>778944 D4E2 EA 1234567891 2018-11-060000001000EA
0000000000000100001020D04YA30TRE0000000XXXYYY 300{ P 2018-11-05</DATA>
</item>
<item>
<DATA>987654 D4E2 EA 1987654321 2018-11-060000002001EA
0000000000000100001020D04YA30UUU0000000XXXLRB 100{ P 2018-11-05</DATA>
</item>
.
.
.
.
.
.
.
.
</T_ER>
</TABLES>
</ZR>
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions" >
<xsl:output omit-xml-declaration="yes"/>
<xsl:param name="break" select="'
'" />
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA"/>
<xsl:value-of select="$break" />
</xsl:template>
</xsl:stylesheet>
预期输出:
HEADER1111111122222222333333344456
778944 D4E2 EA 1234567891 2018-11-06000000100{EA
0000000000000100001020D04YA30TRE0000000XXXYYY 300{ P 2018-11-05
987654 D4E2 EA 1987654321 2018-11-06000000200AEA
0000000000000100001020D04YA30UUU0000000XXXLRB 100{ P 2018-11-05
.
.
.
.
好吧,根据您的规范使用函数 string-length
、substring
和 translate
可以实现为:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output omit-xml-declaration="yes" />
<xsl:param name="break" select="'
'" />
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA" />
<xsl:value-of select="$break" />
<xsl:for-each select="ZR/TABLES/T_ER/item[position() != 1]">
<xsl:variable name="length" select="string-length(substring(DATA,0,46))" />
<xsl:variable name="tenNumbers" select="substring(DATA, ($length + 1), 10)"/>
<xsl:variable name="charToReplace" select="translate(substring($tenNumbers, string-length($tenNumbers), 1),'0123456789','{ABCDEFGHI')" />
<xsl:value-of select="concat(substring(DATA,0,46), substring(DATA, ($length + 1), 9), $charToReplace, substring(DATA,($length+11),(string-length(DATA) + 1)))"/>
<xsl:value-of select="$break" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
看起来你只是想根据你的地图替换第 55 个字符,所以你可以这样做...
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA"/>
<xsl:value-of select="$break" />
<xsl:for-each select="ZR/TABLES/T_ER/item[position() > 1]/DATA">
<xsl:variable name="char" select="substring('{ABCDEFGHI', number(substring(., 55, 1)) + 1, 1)" />
<xsl:value-of select="concat(substring(., 1, 54), $char, substring(., 56))" />
<xsl:value-of select="$break" />
</xsl:for-each>
</xsl:template>
这适用于 XSLT 1.0。
XSLT 2.0 解决方案可能是这样...
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA,
ZR/TABLES/T_ER/item[position() > 1]/DATA/concat(substring(., 1, 54), substring('{ABCDEFGHI', number(substring(., 55, 1)) + 1, 1), substring(., 56))"
separator="
" />
</xsl:template>
在 XSLT 3.0 中,您可以使用 map
,如果您想考虑两个或更多字符,则可以轻松扩展:
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:fn="http://www.w3.org/2005/xpath-functions" >
<xsl:output omit-xml-declaration="yes"/>
<xsl:param name="break" select="'
'" />
<xsl:variable name="chars" as="map(xs:string, xs:string)">
<xsl:map>
<xsl:map-entry key="'0'" select="'{'"/>
<xsl:map-entry key="'1'" select="'A'"/>
<xsl:map-entry key="'2'" select="'B'"/>
<xsl:map-entry key="'3'" select="'C'"/>
<xsl:map-entry key="'4'" select="'D'"/>
<xsl:map-entry key="'5'" select="'E'"/>
<xsl:map-entry key="'6'" select="'F'"/>
<xsl:map-entry key="'7'" select="'G'"/>
<xsl:map-entry key="'8'" select="'H'"/>
<xsl:map-entry key="'9'" select="'I'"/>
</xsl:map>
</xsl:variable>
<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA,
ZR/TABLES/T_ER/item[position() > 1]/DATA/concat(substring(., 1, 54), $chars(substring(., 55, 1)), substring(., 56))" separator="
" />
</xsl:template>
</xsl:stylesheet>
XSLT 3.0 中可能有更好的方法,所以希望 Martin Honnen 很快就会说....