我正在尝试为XML创建通用xslt到CSV。
当特定子项中不可用的元素不会产生空白值且节点
时,会遇到问题是否有可能为不同的xml实现通用xslt,它具有相似的树结构,只有元素节点不同
Root- Child - Element1,Element2 孩子 - Element3 孩子 - Element4
示例输入XML
<?xml version="1.0" encoding="UTF-8"?>
<queryResponse>
<User>
<Id>rti</Id>
</User>
<User>
<Id>qwe</Id>
<EmployeeNumber>emp1</EmployeeNumber>
<IsActive>false</IsActive>
</User>
<User>
<Id>Abc</Id>
<IsActive>false</IsActive>
</User>
<User>
<Id>123</Id>
<EmployeeNumber>emp4</EmployeeNumber>
<IsActive>false</IsActive>
</User>
</queryResponse>
预期产出
"Id","EmployeeNumber","IsActive"
"rti","",""
"qwe","emp1","false"
"Abc","","false"
"123","emp4","false"
&#13;
尝试过XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:param name="delim" select="','" />
<xsl:param name="break" select="'
'" /><!-- xA = NL, xD = CR -->
<xsl:param name="colnames" select="'y'"/>
<xsl:strip-space elements="*" />
<xsl:template match="/*/child::*">
<!--headerline-->
<xsl:if test="$colnames = 'y'">
<!-- <xsl:if test="position() = 1"> -->
<xsl:for-each select="child::*">
<xsl:text>"</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>"</xsl:text>
<xsl:if test="position() != last()">
<xsl:value-of select="$delim"/>
</xsl:if>
</xsl:for-each>
<!-- hardcode version newline -->
<!--<xsl:text>
</xsl:text>-->
<!-- linebreak, nicer -->
<xsl:value-of select="$break" />
<!-- </xsl:if> -->
</xsl:if>
<!--dataline-->
<xsl:for-each select="child::*">
<xsl:if test="position() != last()">
<xsl:text>"</xsl:text>
<xsl:value-of select="normalize-space(.)"/>
<xsl:text>"</xsl:text>
<xsl:value-of select="$delim" />
</xsl:if>
<xsl:if test="position() = last()">
<xsl:text>"</xsl:text>
<xsl:value-of select="normalize-space(.)"/>
<xsl:text>"</xsl:text>
<xsl:value-of select="$break" />
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
&#13;
结果输出
"Id"
"rti"
"qwe","emp1","false"
"Abc","false"
"123","emp4","false"
&#13;
答案 0 :(得分:0)
您需要定义或检测唯一列名称(即第三级元素名称),然后处理每个第二级元素以检查它是否具有这样的列,如果不是输出空字符串。
如果您不局限于XSLT 1但可以使用XSLT 3(由Saxon 9.8或Altova 2017/2018或Exselt 1.1支持),您可以以紧凑的方式执行此操作:
<?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:mf="http://example.com/mf"
exclude-result-prefixes="xs mf"
version="3.0">
<xsl:param name="sep" as="xs:string" select="','"/>
<xsl:param name="lf" as="xs:string" select="' '"/>
<xsl:param name="quote" as="xs:string" select="'"'"/>
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:function name="mf:quote" as="xs:string">
<xsl:param name="input" as="xs:string"/>
<xsl:sequence select="$quote || replace($input, $quote, '$0$0') || $quote"/>
</xsl:function>
<xsl:param name="cols" as="xs:QName*" select="distinct-values(/*/*/*/node-name())"/>
<xsl:template match="/">
<xsl:value-of select="$cols!mf:quote(string())" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
<xsl:apply-templates select="*/*"/>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="for $col in $cols return mf:quote((*[node-name() eq $col], '')[1])" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
</xsl:template>
</xsl:stylesheet>
http://xsltfiddle.liberty-development.net/jyyiVhr的在线示例。
XSLT 2版本位于http://xsltransform.hikmatu.com/bFukv8h,它只使用for .. return ..
代替!
和concat
代替||
:
<?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:mf="http://example.com/mf"
exclude-result-prefixes="xs mf"
version="2.0">
<xsl:param name="sep" as="xs:string" select="','"/>
<xsl:param name="lf" as="xs:string" select="' '"/>
<xsl:param name="quote" as="xs:string" select="'"'"/>
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:function name="mf:quote" as="xs:string">
<xsl:param name="input" as="xs:string"/>
<xsl:sequence select="concat($quote, replace($input, $quote, '$0$0'), $quote)"/>
</xsl:function>
<xsl:param name="cols" as="xs:QName*" select="distinct-values(/*/*/*/node-name(.))"/>
<xsl:template match="/">
<xsl:value-of select="for $col in $cols return mf:quote(string($col))" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
<xsl:apply-templates select="*/*"/>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="for $col in $cols return mf:quote((*[node-name(.) eq $col], '')[1])" separator="{$sep}"/>
<xsl:value-of select="$lf"/>
</xsl:template>
</xsl:stylesheet>