XSLT新手求助:修正JSON转CSV的XSLT select映射问题
Hi there! Let's get your JSON-to-CSV transform working properly. The main issue with your current code is that it's iterating over every element in the XML output from json-to-xml()—but that structure includes container nodes like array and map that you don't want to include in your CSV. Let's break down the fix step by step.
First, Understand the XML from json-to-xml()
Your input JSON:
[{"id":"1","name":"manu"},{"id":"2","name":"vivek"}]
Gets converted to this XML structure by json-to-xml():
<array xmlns="http://www.w3.org/2005/xpath-functions"> <map> <string key="id">1</string> <string key="name">manu</string> </map> <map> <string key="id">2</string> <string key="name">vivek</string> </map> </array>
We need to target the map elements (each represents a JSON object) and then extract the values from their child string elements.
Corrected XSLT Code
Here's the revised code that properly maps the JSON structure to CSV:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" xmlns="http://www.w3.org/2005/xpath-functions" xpath-default-namespace="http://www.w3.org/2005/xpath-functions" expand-text="yes"> <xsl:param name="input"/> <xsl:output method="text"/> <xsl:template name="initial-template"> <!-- Convert JSON to its XML representation --> <xsl:variable name="input-as-xml" select="json-to-xml($input)"/> <!-- Output CSV header row --> <xsl:text>id,name </xsl:text> <!-- Loop through each JSON object (represented by <map> elements) --> <xsl:for-each select="$input-as-xml/array/map"> <!-- Loop through each field in the current object --> <xsl:for-each select="string"> <!-- Handle fields with commas (wrap in quotes per CSV standards) --> <xsl:choose> <xsl:when test="contains(., ',')"> <xsl:text>"</xsl:text> <xsl:value-of select="replace(., '"', '""')"/> <!-- Escape internal quotes --> <xsl:text>"</xsl:text> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> <!-- Add comma separator, except after the last field in the row --> <xsl:if test="position() != last()"> <xsl:text>,</xsl:text> </xsl:if> </xsl:for-each> <!-- New line after each row --> <xsl:text> </xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Key Improvements:
- Targeted Selection: Instead of
//*, we use$input-as-xml/array/mapto iterate only over JSON objects, thenstringto get their field values. - Proper CSV Headers: Added a header row (
id,name) to make the output usable. - CSV-Compliant Handling: If a field value contains commas, we wrap it in double quotes (the standard way to handle this in CSV) and escape any internal double quotes by replacing
"with"". - Clean Row Structure: Each JSON object becomes a single row in the CSV, with fields separated by commas.
Sample Output
When you run this with your input JSON, you'll get this valid CSV:
id,name 1,manu 2,vivek
内容的提问来源于stack exchange,提问作者manu

