我正在使用XSLT 2.0(Saxon处理器)并尝试将xml转换为另一个。以下是样本输入xml的样子
<Customer>
<Name>{{customer_name}}</Name>
<Transaction>{{customer_transaction}}</Transaction>
<Id>134</Id>
</Customer>
如何检查每个xml标记的值,并验证其是否为字段名称,例如customer_name或customer_transaction?如果是字段名称,那么我需要在外部csv文件中查找其值并替换其值。
这是我到目前为止编写的xsl模板。有人可以协助我完成它。
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="fn"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0" exclude-result-prefixes="xs fn">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="csv-uri"
select="'file:///E:/data.csv'"/>
<xsl:variable name="csv" select="unparsed-text($csv-uri)"/>
<!-- Identity template : copy all text nodes, elements and attributes -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:function name="fn:getTokens" as="xs:string+">
<xsl:param name="str" as="xs:string"/>
<xsl:analyze-string select="concat($str, ',')" regex='(("[^"]*")+|[^,]*),'>
<xsl:matching-substring>
<xsl:sequence select='replace(regex-group(1), "^""|""$|("")""", "$1")'/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:variable name="lines" select="tokenize($csv, '\r\n')" as="xs:string+"/>
<xsl:variable name="headerColNames" select="fn:getTokens($lines[1])" as="xs:string+"/>
<xsl:template match="*/text()[starts-with(.,'{{')]">
<!-- add more code here -->
</xsl:template>
</xsl:stylesheet>
如果data.csv具有以下数据
customer_name, customer_transaction
abc, T1
xyz, T2
输出xml应该看起来像
<Customer>
<Name>abc</Name>
<Transaction>T1</Transaction>
<Id>134</Id>
</Customer>
请注意,我们只关注第一条记录。
感谢。
答案 0 :(得分:0)
我会考虑首先将CSV“转换”为XML,然后匹配并选择,这里是一个XSLT 3解决方案(可以转换为XSLT 2,但需要更多代码行,但Saxon 9.8运行XSLT 3):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
expand-text="yes"
version="3.0">
<xsl:param name="csv-uri" as="xs:string">test2017110601.txt</xsl:param>
<xsl:param name="field-pattern" as="xs:string" expand-text="no">\{\{.+\}\}</xsl:param>
<xsl:param name="repl-pattern" as="xs:string" expand-text="no">^\{\{|\}\}$</xsl:param>
<xsl:param name="sep-pattern" as="xs:string">,\s*</xsl:param>
<xsl:param name="csv-lines" as="xs:string*" select="unparsed-text-lines($csv-uri)"/>
<xsl:variable name="col-names" as="xs:string*" select="tokenize(head($csv-lines), $sep-pattern)"/>
<xsl:variable name="csv-doc">
<xsl:apply-templates select="tail($csv-lines)[normalize-space()]" mode="lines"/>
</xsl:variable>
<xsl:key name="fields" match="row/*" use="local-name()"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match=".[. instance of xs:string]" mode="lines">
<row>
<xsl:variable name="cols" as="xs:string*" select="tokenize(., ',\s*')"/>
<xsl:for-each select="$col-names">
<xsl:element name="{.}">{let $p := position() return $cols[$p]}</xsl:element>
</xsl:for-each>
</row>
</xsl:template>
<xsl:template match="*[not(*) and matches(., $field-pattern)]">
<xsl:copy>
<xsl:value-of select="key('fields', replace(., $repl-pattern, ''), $csv-doc)[1]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这是一个XSLT 2版本:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:param name="csv-uri" as="xs:string">test2017110601.txt</xsl:param>
<xsl:param name="field-pattern" as="xs:string">\{\{.+\}\}</xsl:param>
<xsl:param name="repl-pattern" as="xs:string">^\{\{|\}\}$</xsl:param>
<xsl:param name="sep-pattern" as="xs:string">,\s*</xsl:param>
<xsl:param name="csv-lines" as="xs:string*" select="tokenize(unparsed-text($csv-uri), '\r?\n')"/>
<xsl:variable name="col-names" as="xs:string*" select="tokenize($csv-lines[1], $sep-pattern)"/>
<xsl:variable name="csv-doc">
<xsl:for-each select="$csv-lines[position() gt 1][normalize-space()]">
<row>
<xsl:variable name="cols" as="xs:string*" select="tokenize(., ',\s*')"/>
<xsl:for-each select="$col-names">
<xsl:element name="{.}">
<xsl:variable name="p" as="xs:integer" select="position()"/>
<xsl:value-of select="$cols[$p]"/>
</xsl:element>
</xsl:for-each>
</row>
</xsl:for-each>
</xsl:variable>
<xsl:key name="fields" match="row/*" use="local-name()"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*) and matches(., $field-pattern)]">
<xsl:copy>
<xsl:value-of select="key('fields', replace(., $repl-pattern, ''), $csv-doc)[1]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>