问题
I am trying to convert delimiter separated data to tokenize and parse into xml using xsl. Currently I have this
XML
abc|"x|y|z"|gh|ij
XSL
<xsl:template match="/">
<client:SplitString>
<xsl:call-template name="tokenize">
<xsl:with-param name="text"
select="/client:CSVString/client:CSV_Value"/>
</xsl:call-template>
</client:SplitString>
</xsl:template>
<xsl:template match="text/text()" name="tokenize">
<xsl:param name="text" select="$text"/>
<xsl:param name="separator"
select="|"/>
<xsl:choose>
<xsl:when test="not(contains($text, $separator))">
<client:Value>
<xsl:value-of select="normalize-space($text)"/>
</client:Value>
</xsl:when>
<xsl:otherwise>
<client:Value>
<xsl:value-of select="normalize-space(substring-before($text, $separator))"/>
</client:Value>
<xsl:call-template name="tokenize">
<xsl:with-param name="text"
select="substring-after($text, $separator)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This works fine for regular delimiter separated values, but fails on the pipes inside the delimiter. I have the regex for it to recognize the pipe inside quotes as a single value. But i am somehow not able to use it.
"([^"]*)",?|([^|]+),?
I want the result to be
<result>abc</result>
<result>x|y|z</result>
<result>gh</result>
<result>ij</result>
Any kind of help would be appreciated. Thank you!
回答1:
What you can do is check to see if the string to be tokenized starts with a quote. If it does, output what's between the quotes. If it doesn't, tokenize it normally.
Example...
XML Input
<doc>
<value>abc|"x|y|z"|gh|ij</value>
<value>"x|y|z"|abc|gh|ij</value>
<value>abc|"x|y|z"|gh|"x|y|z"|ij</value>
<value>"x|y|z"|abc|"x|y|z"|gh|ij|"x|y|z"</value>
</doc>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="value">
<SplitString>
<xsl:call-template name="tokenize">
<xsl:with-param name="input" select="normalize-space()"/>
</xsl:call-template>
</SplitString>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="delimiter" select="'|'"/>
<xsl:param name="input"/>
<xsl:choose>
<xsl:when test="starts-with($input, '"')">
<xsl:variable name="value" select="substring-before(substring-after($input,'"'),'"')"/>
<result>
<xsl:value-of select="normalize-space($value)"/>
</result>
<xsl:call-template name="tokenize">
<xsl:with-param name="input" select="normalize-space(substring($input,string-length($value)+3))"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="value" select="substring-before(concat($input,$delimiter),$delimiter)"/>
<xsl:if test="string($value)">
<result>
<xsl:value-of select="normalize-space($value)"/>
</result>
</xsl:if>
<xsl:if test="string(substring-after($input,$delimiter))">
<xsl:call-template name="tokenize">
<xsl:with-param name="input" select="normalize-space(substring-after($input,$delimiter))"/>
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Output
<SplitString>
<result>abc</result>
<result>x|y|z</result>
<result>gh</result>
<result>ij</result>
</SplitString>
<SplitString>
<result>x|y|z</result>
<result>abc</result>
<result>gh</result>
<result>ij</result>
</SplitString>
<SplitString>
<result>abc</result>
<result>x|y|z</result>
<result>gh</result>
<result>x|y|z</result>
<result>ij</result>
</SplitString>
<SplitString>
<result>x|y|z</result>
<result>abc</result>
<result>x|y|z</result>
<result>gh</result>
<result>ij</result>
<result>x|y|z</result>
</SplitString>
Fiddle: http://xsltfiddle.liberty-development.net/bFDb2C9/2
来源:https://stackoverflow.com/questions/50684397/csv-to-xml-xslt-how-to-pipe-escape