Hi,
thank you for your good work with bom2groupedCsv.xsl Wolf.
I am but playing around with kicad, so I found the time to adapt it a little to my “needs”.
So I thought, that breaking up the Reference field into multiple lines and also adding some parameters for influencing the generated CSV file would be nice. And so I added the following parameters:
- refcount - determines the maximum count of references per line (default 10).
- d - the CSV field delimiter character (default “,”).
- s - the delimiter character for the references in the “Reference” field (default “,”).
- q - the CSV quote character (one of [’"]) (default ‘"’").
To change them, you can edit the xsl file or add the changed parameter to the command line of the BOM wizard.
As an example, to change the CSV field delimiter to a semicolon ‘;’, you can invoke xsltproc as follows:
xsltproc --stringparam d ";" -o ... (the rest of the command line is unchanged).
Here is the code:
<!--XSL style sheet to convert EESCHEMA XML Partlist Format to grouped CSV BOM Format
Copyright (C) 2014, Wolf Walter.
Copyright (C) 2013, Stefan Helmert.
GPL v2.
Functionality:
Generation of Digi-Key ordering system compatible BOM
How to use this is explained in eeschema.pdf chapter 14. You enter a command line into the
netlist exporter using a new (custom) tab in the netlist export dialog. The command is
on Windows:
xsltproc -o "%O.csv" "pathToFile\bom2groupedCsv.xsl" "%I"
on Linux:
xsltproc -o %O.csv pathToFile/bom2groupedCsv.xsl %I
Extended Functionality:
Quote all fields, so that delimiter characters in a field isn't misinterpreted as a field delimiter.
Limit the count of references per row in the "Reference" field.
Make parameters of some values, so that they can be changed at run time.
Parameters are:
refcount - count of references per row in the field "Reference" - default is 10.
d - field delimiter character - default is ','.
s - reference delimiter character in the field "Reference" - default is ','.
q - field quote character - default is '"'. (the escaped quote character is composed of two quote characters in the CSV format)
To change a parameter, you can edit this file or insert --stringparam param_name param_value after xsltproc in the command above:
xsltproc --stringparam "refcount" "5" --stringparam "d" ";" -o %O.csv pathToFile/bom2groupedCsv.xsl %I
Here -- is used instead of a double hyphen because double hyphens are not allowed in xml comments.
Also only the Linux variant is shown, because the changes are identical for Win and Linux.
-->
<!--
@package
Generate a Tab delimited list (csv file type).
Components of the same type grouped per line
Fields are
Ref, Quantity, Value, Footprint, Datasheet, Field6, Field7, ...
-->
<!DOCTYPE xsl:stylesheet [
<!ENTITY nl "
"> <!--new line CR, LF, or LF, your choice -->
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<!-- parameter for count of references -->
<xsl:param name="refcount">10</xsl:param>
<!-- parameter for field delimiter -->
<xsl:param name="d">,</xsl:param> <!-- a field delimiter character (FDC) of your choice - one of ',' or ';' -->
<!-- parameter for reference delimiter -->
<xsl:param name="s">,</xsl:param> <!-- an in-field reference delimiter character of your choice -->
<!-- parameter for quotes -->
<xsl:param name="q">"</xsl:param> <!-- a quote character (QC) of your choice - one of '"' or "'" -->
<!-- for Muenchian grouping of footprint and value combination -->
<xsl:key name="partTypeByValueAndFootprint" match="comp" use="concat(footprint, '-', value)" />
<!-- for table head and empty table fields-->
<xsl:key name="headentr" match="field" use="@name"/>
<!-- replacing template -->
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- main part -->
<xsl:template match="/export">
<xsl:value-of select="$q" />
<xsl:text>Reference</xsl:text>
<xsl:value-of select="$q" />
<xsl:value-of select="$d" /><xsl:text> </xsl:text>
<xsl:value-of select="$q" />
<xsl:text>Quantity</xsl:text>
<xsl:value-of select="$q" />
<xsl:value-of select="$d" /><xsl:text> </xsl:text>
<xsl:value-of select="$q" />
<xsl:text>Value</xsl:text>
<xsl:value-of select="$q" />
<xsl:value-of select="$d" /><xsl:text> </xsl:text>
<xsl:value-of select="$q" />
<xsl:text>Footprint</xsl:text>
<xsl:value-of select="$q" />
<xsl:value-of select="$d" /><xsl:text> </xsl:text>
<xsl:value-of select="$q" />
<xsl:text>Datasheet</xsl:text>
<xsl:value-of select="$q" />
<!-- find all existing table head entries and list each one once -->
<!-- if the QC is found in the value of the column header, replace it with two QC -->
<xsl:for-each select="components/comp/fields/field[generate-id(.) = generate-id(key('headentr',@name)[1])]">
<xsl:value-of select="$d" /><xsl:text> </xsl:text>
<xsl:value-of select="$q" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="@name" />
<xsl:with-param name="replace" select="$q" />
<xsl:with-param name="by" select="concat($q,$q)" />
</xsl:call-template>
<xsl:value-of select="$q" />
</xsl:for-each>
<!-- all table entries -->
<xsl:apply-templates select="components"/>
</xsl:template>
<xsl:template match="components">
<!-- for Muenchian grouping of footprint and value combination -->
<xsl:for-each select="comp[count(. | key('partTypeByValueAndFootprint', concat(footprint, '-', value))[1]) = 1]">
<xsl:sort select="@ref" />
<xsl:text>&nl;</xsl:text>
<!-- list of all references -->
<xsl:value-of select="$q" />
<xsl:for-each select="key('partTypeByValueAndFootprint', concat(footprint, '-', value))">
<xsl:sort select="@ref" />
<xsl:value-of select="@ref"/>
<xsl:if test="position() != last()">
<xsl:choose>
<xsl:when test="(position() > 0) and (position() mod $refcount) != 0">
<xsl:value-of select="$s" /><xsl:text> </xsl:text>
</xsl:when>
<xsl:when test="(position() > 0) and (position() mod $refcount) = 0">
<xsl:value-of select="$s" /><xsl:text>&nl;</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:if>
</xsl:for-each>
<xsl:value-of select="$q" /><xsl:value-of select="$d" />
<!-- quantity of parts with same footprint and value -->
<xsl:value-of select="$q" />
<xsl:value-of select="count(key('partTypeByValueAndFootprint', concat(footprint, '-', value)))"/>
<xsl:value-of select="$q" /><xsl:value-of select="$d" />
<xsl:value-of select="$q" />
<xsl:value-of select="value"/>
<xsl:value-of select="$q" /><xsl:value-of select="$d" />
<xsl:value-of select="$q" />
<xsl:value-of select="footprint"/>
<xsl:value-of select="$q" /><xsl:value-of select="$d" />
<xsl:value-of select="$q" />
<xsl:value-of select="datasheet"/>
<xsl:value-of select="$q" />
<xsl:apply-templates select="fields"/>
</xsl:for-each>
</xsl:template>
<!-- table entries with dynamic table head -->
<xsl:template match="fields">
<!-- remember current fields section -->
<xsl:variable name="fieldvar" select="field"/>
<!-- for all existing head entries -->
<xsl:for-each select="/export/components/comp/fields/field[generate-id(.) = generate-id(key('headentr',@name)[1])]">
<xsl:variable name="allnames" select="@name"/>
<xsl:value-of select="$d" />
<!-- for all field entries in the remembered fields section -->
<xsl:for-each select="$fieldvar">
<!-- only if this field entry exists in this fields section -->
<xsl:if test="@name=$allnames">
<!-- content of the field -->
<!-- if the QC is found in the value, replace it with two QC -->
<xsl:value-of select="$q" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="." />
<xsl:with-param name="replace" select="$q" />
<xsl:with-param name="by" select="concat($q,$q)" />
</xsl:call-template>
<xsl:value-of select="$q" />
</xsl:if>
<!--
If it does not exist, use an empty cell in output for this row.
Every non-blank entry is assigned to its proper column.
-->
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>