tes*_*ser 3 .net c# xslt fixed-length-record
我试图找到一个更好的解决方案,将纯文本(但每个字段的预定义长度)转换为xml.例如,输入文本可以是"Testuser new york 10018",前11个字符表示用户名,接下来的12个字符表示城市,接下来的5个字符表示邮政编码.所以我需要使用预定义的字段长度从上面的字符串形成一个xml.
我在想两种方法
通过在输入文本上使用子字符串函数定义业务实体并填充实体属性,然后将实体序列化为xml
预定义xml结构,使用xslt导航到每个节点并使用输入文本上的子字符串函数填充值.
声明:(XSLT)"isn't suitable for transforming from structured text to XML. "和声明"XSLTmusthave XML as the input document"**都是错误的.
我在想两种方法
通过在输入文本上使用子字符串函数定义业务实体并填充实体属性,然后将实体序列化为xml
预定义xml结构,使用xslt导航到每个节点并使用输入文本上的子字符串函数填充值.
事实上,使用XSLT很容易实现方法2:
I. XSLT 1.0:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*/text()" name="processLines">
<xsl:param name="pText" select="."/>
<xsl:if test="contains($pText, '
')">
<xsl:variable name="vLine" select=
"substring-before($pText, '
')"/>
<user>
<name>
<xsl:value-of select=
"translate(substring-before($vLine, ' '),'_',' ')"/>
</name>
<city>
<xsl:value-of select=
"translate(substring-before(substring-after($vLine, ' '),' '),
'_',
' '
)
"/>
</city>
<zipCode>
<xsl:value-of select=
"translate(substring-after(substring-after($vLine, ' '),' '),
'_',
' '
)
"/>
</zipCode>
</user>
<xsl:call-template name="processLines">
<xsl:with-param name="pText" select=
"substring-after($pText, '
')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当这个转换应用于特殊格式的文本时(包含在单个顶部元素中以使格式正确 - 我们将在XSLT 2.0中看到这样的包装不是必需的):
<t>Testuser new_york 10018
usera seattle 98000
userb bellevue 98004
userb redmond 98052
</t>
Run Code Online (Sandbox Code Playgroud)
产生了想要的结果:
<user>
<name>Testuser</name>
<city>new york</city>
<zipCode>10018</zipCode>
</user>
<user>
<name>usera</name>
<city>seattle</city>
<zipCode>98000</zipCode>
</user>
<user>
<name>userb</name>
<city>bellevue</city>
<zipCode>98004</zipCode>
</user>
<user>
<name>userb</name>
<city>redmond</city>
<zipCode>98052</zipCode>
</user>
Run Code Online (Sandbox Code Playgroud)
备注:
这只是演示如何完成任务的演示.这就是为什么我不处理固定宽度的字段(稍微更容易),而是空格分隔值.
包含在任何值中的任何空格都作为下划线输入输入(或我们选择的任何字符,我们知道它们永远不会成为任何值的一部分.在输出中,任何下划线都会转换为真实空间.
II.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:variable name="vText" select=
"unparsed-text('file:///c:/temp/delete/delete.txt')"/>
<xsl:variable name="vLines" select=
"tokenize($vText, '
?
')[normalize-space()]"/>
<xsl:template match="/">
<xsl:for-each select="$vLines">
<xsl:variable name="vFields" select=
"tokenize(., ' ')[normalize-space()]"/>
<user>
<name>
<xsl:sequence select="translate($vFields[1], '_',' ')"/>
</name>
<city>
<xsl:sequence select="translate($vFields[2], '_',' ')"/>
</city>
<zipCode>
<xsl:sequence select="translate($vFields[3], '_',' ')"/>
</zipCode>
</user>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当这个转换应用于任何XML文档时(未使用且实际上不需要,如在XSLT 2.0中,没有必要具有源XML文档),并且如果文件C:\temp\delete\delete.txt是:
Testuser new_york 10018
usera seattle 98000
userb bellevue 98004
userb redmond 98052
Run Code Online (Sandbox Code Playgroud)
再次产生想要的,正确的结果:
<user>
<name>Testuser</name>
<city>new york</city>
<zipCode>10018</zipCode>
</user>
<user>
<name>usera</name>
<city>seattle</city>
<zipCode>98000</zipCode>
</user>
<user>
<name>userb</name>
<city>bellevue</city>
<zipCode>98004</zipCode>
</user>
<user>
<name>userb</name>
<city>redmond</city>
<zipCode>98052</zipCode>
</user>
Run Code Online (Sandbox Code Playgroud)
备注:
使用标准的XSLT 2.0功能unparsed-text().
使用标准的XPath 2.0功能tokenize().
最后的说明:
大多数复杂的文本处理都是在XSLT中以工业方式完成的.FXSL库包含一个通用的LR(1)解析器和一个调整后的YACC,它生成XML格式的表,这些表是这个通用运行时LR(1)解析器的输入.
使用此工具,我成功为JSON和XPath 2.0等复杂语言构建了解析器.