Ich habe das folgende XML-Dokument:
<projects>
<project>
<name>Shockwave</name>
<language>Ruby</language>
<owner>Brian May</owner>
<state>New</state>
<startDate>31/10/2008 0:00:00</startDate>
</project>
<project>
<name>Other</name>
<language>Erlang</language>
<owner>Takashi Miike</owner>
<state> Canceled </state>
<startDate>07/11/2008 0:00:00</startDate>
</project>
...
Und ich möchte dies aus dem Ergebnis der Transformation (XSLT) erhalten:
Shockwave,Ruby,Brian May,New,31/10/2008 0:00:00
Other,Erlang,Takashi Miike,Cancelled,07/11/2008 0:00:00
Kennt jemand das XSLT, um dies zu erreichen? Ich benutze .net für den Fall, dass es darauf ankommt.
Antworten:
Hier wurde ein XML-Transformations-Stylesheet gefunden (Wayback-Maschinenlink, Site selbst ist auf Deutsch)
Das hier hinzugefügte Stylesheet könnte hilfreich sein:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="iso-8859-1"/> <xsl:strip-space elements="*" /> <xsl:template match="/*/child::*"> <xsl:for-each select="child::*"> <xsl:if test="position() != last()">"<xsl:value-of select="normalize-space(.)"/>", </xsl:if> <xsl:if test="position() = last()">"<xsl:value-of select="normalize-space(.)"/>"<xsl:text>
</xsl:text> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Vielleicht möchten Sie die Anführungszeichen in xsl entfernen: if-Tags, damit Ihre Werte nicht in Anführungszeichen gesetzt werden, je nachdem, wo Sie die CSV-Datei verwenden möchten.
quelle
,
'), das Anführungszeichen ('"
'), eine neue Zeile (
). Wenn Anführungszeichen erforderlich sind, müssen alle inneren Anführungszeichen zuerst verdoppelt werden ('""
').
(\ n).
ist hexadezimal \ rHier ist eine Version mit konfigurierbaren Parametern, die Sie programmgesteuert einstellen können:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="utf-8" /> <xsl:param name="delim" select="','" /> <xsl:param name="quote" select="'"'" /> <xsl:param name="break" select="'
'" /> <xsl:template match="/"> <xsl:apply-templates select="projects/project" /> </xsl:template> <xsl:template match="project"> <xsl:apply-templates /> <xsl:if test="following-sibling::*"> <xsl:value-of select="$break" /> </xsl:if> </xsl:template> <xsl:template match="*"> <!-- remove normalize-space() if you want keep white-space at it is --> <xsl:value-of select="concat($quote, normalize-space(), $quote)" /> <xsl:if test="following-sibling::*"> <xsl:value-of select="$delim" /> </xsl:if> </xsl:template> <xsl:template match="text()" /> </xsl:stylesheet>
quelle
Dies
xsl:stylesheet
kann eine angegebene Liste von Spaltenüberschriften verwenden und stellt sicher, dass die Zeilen korrekt sortiert werden.<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:csv="csv:csv"> <xsl:output method="text" encoding="utf-8" /> <xsl:strip-space elements="*" /> <xsl:variable name="delimiter" select="','" /> <csv:columns> <column>name</column> <column>sublease</column> <column>addressBookID</column> <column>boundAmount</column> <column>rentalAmount</column> <column>rentalPeriod</column> <column>rentalBillingCycle</column> <column>tenureIncome</column> <column>tenureBalance</column> <column>totalIncome</column> <column>balance</column> <column>available</column> </csv:columns> <xsl:template match="/property-manager/properties"> <!-- Output the CSV header --> <xsl:for-each select="document('')/*/csv:columns/*"> <xsl:value-of select="."/> <xsl:if test="position() != last()"> <xsl:value-of select="$delimiter"/> </xsl:if> </xsl:for-each> <xsl:text>
</xsl:text> <!-- Output rows for each matched property --> <xsl:apply-templates select="property" /> </xsl:template> <xsl:template match="property"> <xsl:variable name="property" select="." /> <!-- Loop through the columns in order --> <xsl:for-each select="document('')/*/csv:columns/*"> <!-- Extract the column name and value --> <xsl:variable name="column" select="." /> <xsl:variable name="value" select="$property/*[name() = $column]" /> <!-- Quote the value if required --> <xsl:choose> <xsl:when test="contains($value, '"')"> <xsl:variable name="x" select="replace($value, '"', '""')"/> <xsl:value-of select="concat('"', $x, '"')"/> </xsl:when> <xsl:when test="contains($value, $delimiter)"> <xsl:value-of select="concat('"', $value, '"')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$value"/> </xsl:otherwise> </xsl:choose> <!-- Add the delimiter unless we are the last expression --> <xsl:if test="position() != last()"> <xsl:value-of select="$delimiter"/> </xsl:if> </xsl:for-each> <!-- Add a newline at the end of the record --> <xsl:text>
</xsl:text> </xsl:template> </xsl:stylesheet>
quelle
replace()
ist eine XPath 2.0-Funktion. In XSLT 1.0 müssten Sie eine rekursive Zeichenfolgenersetzungsvorlage verwenden.Diese
CsvEscape
Funktion ist XSLT 1.0 und entweicht Spaltenwerte,
,"
und neue Zeilen wie RFC 4180 oder Excel. Es nutzt die Tatsache, dass Sie XSLT-Vorlagen rekursiv aufrufen können:EscapeQuotes
ersetzt alle doppelten Anführungszeichen rekursiv ab dem Anfang der Zeichenfolge durch zwei doppelte Anführungszeichen.CsvEscape
prüft, ob der Text ein Komma oder ein doppeltes Anführungszeichen enthält, und umgibt in diesem Fall die gesamte Zeichenfolge mit zwei doppelten Anführungszeichen und fordertEscapeQuotes
die Zeichenfolge auf.Anwendungsbeispiel:
xsltproc xmltocsv.xslt file.xml > file.csv
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="UTF-8"/> <xsl:template name="EscapeQuotes"> <xsl:param name="value"/> <xsl:choose> <xsl:when test="contains($value,'"')"> <xsl:value-of select="substring-before($value,'"')"/> <xsl:text>""</xsl:text> <xsl:call-template name="EscapeQuotes"> <xsl:with-param name="value" select="substring-after($value,'"')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$value"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="CsvEscape"> <xsl:param name="value"/> <xsl:choose> <xsl:when test="contains($value,',')"> <xsl:text>"</xsl:text> <xsl:call-template name="EscapeQuotes"> <xsl:with-param name="value" select="$value"/> </xsl:call-template> <xsl:text>"</xsl:text> </xsl:when> <xsl:when test="contains($value,'
')"> <xsl:text>"</xsl:text> <xsl:call-template name="EscapeQuotes"> <xsl:with-param name="value" select="$value"/> </xsl:call-template> <xsl:text>"</xsl:text> </xsl:when> <xsl:when test="contains($value,'"')"> <xsl:text>"</xsl:text> <xsl:call-template name="EscapeQuotes"> <xsl:with-param name="value" select="$value"/> </xsl:call-template> <xsl:text>"</xsl:text> </xsl:when> <xsl:otherwise> <xsl:value-of select="$value"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="/"> <xsl:text>project,name,language,owner,state,startDate</xsl:text> <xsl:text>
</xsl:text> <xsl:for-each select="projects/project"> <xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(name)"/></xsl:call-template> <xsl:text>,</xsl:text> <xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(language)"/></xsl:call-template> <xsl:text>,</xsl:text> <xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(owner)"/></xsl:call-template> <xsl:text>,</xsl:text> <xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(state)"/></xsl:call-template> <xsl:text>,</xsl:text> <xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(startDate)"/></xsl:call-template> <xsl:text>
</xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
quelle