Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A KiCad BOM script for generating JLCPCB PCBA-compatible files!
<!--XSL style sheet to convert EESCHEMA XML Partlist Format to grouped CSV BOM Format
Copyright (C) 2014, Wolf Walter.
Copyright (C) 2013, Stefan Helmert.
Copyright (C) 2018, Kicad developers.
Copyright (C) 2019, arturo182.
GPL v2.
Functionality:
Generation of JLCPCB PCBA 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 line is
xsltproc -o "%O.csv" "FullPathToFile/bom2grouped_csv_jlcpcb.xsl" "%I"
-->
<!--
@package
Generates a JLCPCB PCBA service compatible BOM
Functionality:
* Generate a comma separated value BOM list (csv file type).
* Components are sorted by ref and grouped by same value+footprint
One value per line
Fields are
Comment,Designator,Footprint,LCSC
The command line is
xsltproc -o "%O.csv" "full_path/bom2grouped_csv_jlcpcb.xsl" "%I"
-->
<!DOCTYPE xsl:stylesheet [
<!ENTITY nl "&#xd;&#xa;"> <!--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"/>
<xsl:variable name="digits" select="'1234567890'" />
<!-- for matching 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"/>
<!-- main part -->
<xsl:template match="/export">
<xsl:text>Comment,Designator,Footprint,LCSC</xsl:text>
<!-- 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>
<xsl:text>"</xsl:text><xsl:value-of select="value"/><xsl:text>","</xsl:text>
<!-- list of all references -->
<xsl:for-each select="key('partTypeByValueAndFootprint', concat(footprint, '-', value))">
<!-- strip non-digits from reference and sort based on remaining number -->
<xsl:sort select="translate(@ref, translate(@ref, $digits, ''), '')" data-type="number" />
<xsl:value-of select="@ref"/>
<xsl:if test="position() != last()"><xsl:text>,</xsl:text></xsl:if>
</xsl:for-each>
<xsl:text>","</xsl:text>
<xsl:value-of select="footprint"/><xsl:text>","</xsl:text>
<xsl:value-of select="fields/field[@name='LCSC']"/><xsl:text>"</xsl:text>
</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:text>,"</xsl:text>
<!-- 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 -->
<xsl:value-of select="."/>
</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:text>"</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
@gregsimon
Copy link

The script has trouble with spaces on Windows. Move it to a (full path) without spaces worked for me.

@heidnerd
Copy link

heidnerd commented Oct 16, 2021

The script has trouble with spaces on Windows. Move it to a (full path) without spaces worked for me.

The problem is xsltproc can't support spaces and some of the other windows path name conventions. The script itself is okay.

We should be reporting the xsltproc problem with windows to their bug reporting site.

http://www.xmlsoft.org/bugs.html

@tormyvancool
Copy link

The script has trouble with spaces on Windows. Move it to a (full path) without spaces worked for me.

The problem is xsltproc can't support spaces and some of the other windows path name conventions. The script itself is okay.

We should be reporting the xsltproc problem with windows to their bug reporting site.

http://www.xmlsoft.org/bugs.html

Ok I sent an email posting the link here and asking for the support of spaces and special characters.
We are in 2021, and these not-compatibilities should be just an ugly memory of the past

@gcormier
Copy link

gcormier commented Dec 2, 2021

inspired me to make this one

https://gist.github.com/gcormier/61addd28226bfd4ed6f645f312c3f13a

it will export your BOM and also update your POS file if it already exists to the JLCPCB header format

@abelflix
Copy link

abelflix commented Sep 6, 2022

Hi, I get this issue trying to generate the BOM. At least, more than 60% of the components are in stock at JLCPCBs part library. I don't want the rest of the parts to be assembled by JLCPCB since I already have the components.

imagen

@1technick
Copy link

Hi, It fails with a file error in version 6.0.9. 6.0.8 was ok. (windows 10 64)
Kicad plans to support only python in future so this may not work at all soon.
In my opinion it is much easier to debug python code so that is what i will do ;-)

@GadgetNutt
Copy link

GadgetNutt commented Mar 14, 2023

Hi.` The xsltproc appears to have been removed from KiCAD 7. Here is a solution:

Keep the instructions currently, but one slight change. Create a new .py file with the same name and put it in the same folder as bom2grouped_csv_jlcpcb.xsl and create the file with:

import lxml.etree as ET
import csv
import sys

# Get the command line arguments
xml_path = sys.argv[1]
csv_path = sys.argv[2]

def generate_bom(xml_path, csv_path):
# Load the EESCHEMA XML Partlist Format file
tree = ET.parse(xml_path)
root = tree.getroot()

# Define the namespace for the XML file
ns = {"xsl": "http://www.w3.org/1999/XSL/Transform"}

# Load the XSL stylesheet to transform the XML file to CSV
xslt_tree = ET.parse("<setpathto>/KiCad/6.0/plugins/bom2grouped_csv_jlcpcb.xsl")
transform = ET.XSLT(xslt_tree)

# Apply the transformation to the XML file
csv_data = transform(root)

# Convert the XSLTResultTree object to a string and split into lines
csv_data_str = str(csv_data)
csv_lines = csv_data_str.splitlines()

# Write the transformed CSV data to file
with open(csv_path, "w", newline="") as csvfile:
writer = csv.writer(csvfile, delimiter=",", quotechar="'", quoting=csv.QUOTE_NONE)
for line in csv_lines:
writer.writerow(line.split(","))

# Example usage
generate_bom(xml_path, csv_path)

and set the commandline to:
python "\KiCad\6.0\plugins\bom2grouped_csv_jlcpcb.py" "%I" "%O.csv"

@amazed-2022
Copy link

amazed-2022 commented Mar 18, 2023

Hi.` The xsltproc appears to have been removed from KiCAD 7. Here is a solution:

Keep the instructions currently, but one slight change. Create a new .py file with the same name and put it in the same folder as bom2grouped_csv_jlcpcb.xsl and create the file.

and set the commandline to: python "\KiCad\6.0\plugins\bom2grouped_csv_jlcpcb.py" "%I" "%O.csv"

Hello, thanks for the update, unfortunately it is not working for me. :(
I get the following error:

    tree = ET.parse(xml_path)
    ^
IndentationError: expected an indented block

How could I make it work?

@tormyvancool
Copy link

Hi.` The xsltproc appears to have been removed from KiCAD 7. Here is a solution:
Keep the instructions currently, but one slight change. Create a new .py file with the same name and put it in the same folder as bom2grouped_csv_jlcpcb.xsl and create the file.
and set the commandline to: python "\KiCad\6.0\plugins\bom2grouped_csv_jlcpcb.py" "%I" "%O.csv"

Hello, thanks for the update, unfortunately it is not working for me. :( I get the following error:

    tree = ET.parse(xml_path)
    ^
IndentationError: expected an indented block

How could I make it work?

If you install this, it should work fine. The full package for JLCPCB is created without any issue and in a subdir called "Production"
image

@amazed-2022
Copy link

If you install this, it should work fine. The full package for JLCPCB is created without any issue and in a subdir called "Production"

Thank you very much for the hint!

@JosephLL753
Copy link

I am still lost with this.

I have installed the Fabrication Toolkit, and created the .py file with the name bom2grouped_csv_jlcpcb.py, but I am still receiving the error code:
tree = ET.parse(xml_path)
^
IndentationError: expected an indented block

@amazed-2022
Copy link

amazed-2022 commented Mar 29, 2023

I am still lost with this.

You don't need the bom2grouped_csv_jlcpcb stuff at all!

Just use the "Fabrication Toolkit" button in the PCB Editor.

kép

@GadgetNutt
Copy link

I am still lost with this.

I have installed the Fabrication Toolkit, and created the .py file with the name bom2grouped_csv_jlcpcb.py, but I am still receiving the error code: tree = ET.parse(xml_path) ^ IndentationError: expected an indented block

Did you install Python and the lxml library?

@tormyvancool
Copy link

I am still lost with this.

You don't need the bom2grouped_csv_jlcpcb stuff at all!

Just use the "Fabrication Toolkit" button in the PCB Editor.

kép

Indeed I also posted how to get it (see a couple of replies above your one) ... but it seems ppl is not reading instructions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment