GithubHelp home page GithubHelp logo

elixlsx's Introduction

Elixlsx

Build Status Module Version Hex Docs Total Download License Last Updated

Elixlsx is a writer for the MS Excel OpenXML format (.xlsx).

Features:

  • Multiple (named) sheets with custom column widths & column heights.
  • (Unicode-)strings, Numbers, Dates
  • Font formatting (size, bold, italic, underline, strike)
  • Horizontal alignment and text wrapping
  • Font and cell background color, borders
  • Merged cells

Installation

As of version 0.6, elixlsx requires Elixir 1.12 or above.

Installation via Hex, in mix.exs:

defp deps do
  [{:elixlsx, "~> 0.6.0"}]
end

Via GitHub:

defp deps do
  [{:elixlsx, github: "xou/elixlsx"}]
end

Usage

1-Line tutorial:

(alias Elixlsx.Workbook, alias Elixlsx.Sheet)
iex(1)> Workbook.append_sheet(%Workbook{}, Sheet.with_name("Sheet 1") |> Sheet.set_cell("A1", "Hello", bold: true)) |> Elixlsx.write_to("hello.xlsx")

See example.exs for examples how to use the various features.

  • The workbook is a XML file ultimately, so remember that formulas containing "<" or ">" must be escaped properly.
  • :xmerl_lib.export_text/1 can be used to escape formulas properly

Number and date formatting reference

A quick introduction how number formattings look like can be found here.

License

Copyright (c) 2015 Nikolai Weh

This library is MIT licensed. See the LICENSE for details.

elixlsx's People

Contributors

0xradical avatar alexkovalevych avatar andershansson avatar antedeguemon avatar azhi avatar bens-spiceworks avatar brandonparsons avatar brucepom avatar elijahkim avatar fabi755 avatar filipows avatar goravbhootra avatar izzyelwyn avatar joeman29 avatar kianmeng avatar leifg avatar mikebaldry avatar mtannaan avatar natanaelsirqueira avatar nippysaurus avatar nkezhaya avatar pavelgnom avatar roehst avatar rrmartins avatar ryanhart2 avatar seelowbei avatar thevole avatar tomciopp avatar xosdy avatar xou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elixlsx's Issues

Formula FILTERXML could not be evaluated without an acceptance

Hello,

For a code like:

alias Elixlsx.Sheet
alias Elixlsx.Workbook

sheet1 = Sheet.with_name("First")
      |> Sheet.set_cell("A1", {:formula, "FILTERXML(A2,\"//price\")"})
      |> Sheet.set_cell("A2",
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?><pricing><price>0.9</price></pricing>"
      )

%Workbook{sheets: [sheet1]}
    |> Elixlsx.write_to("example.xlsx")

The formula FILTERXML is considered as an invalid name.
1

Graphically, it's can be regulated like a valid name with a manual acceptance of the formula.
2
3

Column height not working

I use the Elixlsx.Sheet.set_row_height/2 function for change the height. But the row height is not changed. The code snippet from the example.exs does not work too.

OS: Mac OS X
Software: Microsoft Excel for Mac (2016)

I will try to find and solve the problem.

Office For Mac, reports error and discards styles when opening file

Thanks for the great project!

This can be reproduced by creating the simplest possible file then trying to open it in Microsoft Excel for Mac (https://products.office.com/en-ca/buy/compare-microsoft-office-products?tab=tabs-2).

For example if you run the example from the readme:

Workbook.append_sheet(%Workbook{}, Sheet.with_name("Sheet 1") |> Sheet.set_cell("A1", "Hello", bold: true)) |> Elixlsx.write_to("hello.xlsx")

Then open the resulting file with Office for Mac results in the following warning:

image

If you click "Open and Repair" the file will open but be displayed with no styling and a prompt as follows:
image

If you click "View" to see the log you'll see:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><logFileName>Repair Result to hello1050.xml</logFileName><summary>Errors were detected in file '/Users/bruce/Work/viewprogis/viewprogis_web/vpg/hello105.xlsx'</summary><removedParts summary="Following is a list of removed parts:"><removedPart>Removed Part: /xl/styles.xml with XML error.  (Styles) Load error. Line 36, column 36.</removedPart></removedParts><repairedRecords summary="Following is a list of repairs:"><repairedRecord>Repaired Records: Cell information from /xl/worksheets/sheet1.xml</repairedRecord><repairedRecord>Repaired Records: Cell information from /xl/worksheets/sheet2.xml</repairedRecord></repairedRecords></recoveryLog>

Suggesting a problem with xl/styles.xml

I think I have found a solution and will submit a pull request soon.

Performance issue when writing large data

For some reason I need to generate a very large excel file, which has 700 cols and 13,000 rows. On my 4 core server it takes nearly 30 minutes to write file.

Because the file is created at the very end of the process (and is fast), I guess the bottle neck is on generating the XML in memory. But I'm not sure if it's an Elixir performance issue or this library's. I also have several steps to transform the data to %Worksheet{} (without stream), and it's very fast.

Is it possible to embed images?

I have a workflow where I'm generating the .xlsx and uploading it to S3.

Would it be possible to embed an image either by reading a file or by using a Base64 encoding?

If the current version does not support this would it be technically feasible to add such a feature?

New Release?

This PR fixed a Dialyzer issue in the write_to_memory function. Can we get a bump on Hex so that users can get this fix without specifying the GitHub dependency?

Add support for Date

I want to be able to add a Date ~D[2020-02-27]

My current solution is to change it to {Date.to_erl(date), {0, 0, 0}} with the option yyyymmdd: true but I would like to not have to pass in the tuple.

Can't use "&" in sheet name

Hi there, I've encountered a problem when a sheet's name contains an & character the generated file can't be opened by excel.

To reproduce:
%Workbook{sheets: [%Sheet{name: "elix & lsx"}]} |> Elixlsx.write_to("elixlsx-test.xlsx")

At first I thought that maybe & characters were not allowed in sheet names, but I can use them when working within excel, is this an expected behavior?

ps. Thanks for your work on this library!

Template XLSX

Would it be possible to open an already existing XLSX and only change the text of certain cells?

Rich Text

Is it possible to use rich text in the cells?
That is, to partially format the text?

Generate XLSX using Lists.

  • This is not an issue, this is a propose to enhancement and a question.

There's a function to generate the spreadsheet passing only a list and then auto generate a XLSX that each line(cell line) represents each value in the List???

Office For Mac reports error when freezing only top row

When setting Elixlsx.Sheet pane_freeze to {1, 0}, MS Office on Mac OS complains about corrupted file with

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
  <logFileName>freeze_bug.xlsx</logFileName>
  <summary>Errors were detected in file 'freeze_bug.xlsx'</summary>
  <removedFeatures summary="Following is a list of removed features:">
    <removedFeature>Removed Feature: View from /xl/worksheets/sheet1.xml part</removedFeature>
  </removedFeatures>
</recoveryLog>

Minimal reproduction:

require Elixlsx

alias Elixlsx.Sheet
alias Elixlsx.Workbook

sheet1 = Sheet.with_name("Freeze bug")
         |> Sheet.set_cell("A1", "Header")
         |> Sheet.set_cell("B1", "value")
         |> Sheet.set_pane_freeze(1, 0)
workbook = %Workbook{sheets: [sheet1]}

Elixlsx.write_to(workbook, "freeze_bug.xlsx")

What kind of performance is to be expected?

Right now we have a 2.5mb spreadsheet being generated, and the call to write_to_memory/2 takes about 25 seconds. Is this more than normal, or should we be investigating a cause?

Regardless it would be a very high priority for us to make this faster.

Wrong background set

Trying to set cell background color like this:

rows = [ [ [5], [35], [235, bg_color: "#ffff00"]  ] ]
sheet  = %Sheet{rows: rows}
workbook = %Workbook{sheets: [sheet]}
{:ok, excel} =  Elixlsx.write_to(workbook, "example.xlsx")

In result getting 3-rd cell with white background, the rest cells have yellow background. Expecting an opposite result.

Dialyzer warning on Elixlsx.write_to_memory/2

The pattern {'ok', {__filename@1, _binary@1}} can never match the type {'error',_}

Using Elixir 1.7.3 and Elixlsx 0.4.0:

 defmodule Foo do
   require Elixlsx

   alias Elixlsx.Sheet
   alias Elixlsx.Workbook

   @spec generate_report() :: binary()
   def generate_report() do
     sheet =
       Sheet.with_name("OSHA")
       |> Sheet.set_cell("B1", "wat")

     filename = "filename.xlsx"

     {:ok, {_filename, binary}} =
       %Workbook{sheets: [sheet]}
       |> Elixlsx.write_to_memory(filename)

     binary
   end
 end

Feature request: Set cell background color

Hey!

I was playing around with your library and it works quite nicely, however i would like to set the background color for the cells.
Is there an option i missed or would it be possible to add?

Strings not working

In 0.4.2 trying to create a sheet with any string causes a function XML.valid?/1 is undefined or private error. Think this is related to this change https://github.com/xou/elixlsx/pull/86/files#diff-602217924496a0bfead8d52a018857f7R28

Running through the examples here with 0.4.2 don't work as long as any string is present in any row. Removing all instances of strings lets the library work as intended.

I've verified that going down a version to 0.4.1 fixes the issue with strings.

Warnings with Elixir 1.5.2

Hello,

I got couple of warnings with Elixir 1.5.2 and version 0.3.0:

warning: String.to_char_list/1 is deprecated, use String.to_charlist/1
  lib/elixlsx/writer.ex:112

warning: String.to_char_list/1 is deprecated, use String.to_charlist/1
  lib/elixlsx/util.ex:56

warning: String.to_char_list/1 is deprecated, use String.to_charlist/1
  lib/elixlsx/util.ex:63

warning: the char_list() type is deprecated, use charlist()
  lib/elixlsx/writer.ex:9

warning: defp style_to_xml_entry/2 is private, @doc's are always discarded for private functions/macros/types
  lib/elixlsx/xml_templates.ex:369

warning: defp make_style_alignment/1 is private, @doc's are always discarded for private functions/macros/types
  lib/elixlsx/xml_templates.ex:440

warning: defp make_cellxfs/2 is private, @doc's are always discarded for private functions/macros/types
  lib/elixlsx/xml_templates.ex:457

Dialyzer warning on Workbook.append_sheet()

This code, as given in the doc example, works but generates a dialyzer warning about breaking the contract:

Workbook.append_sheet(%Workbook{}, Sheet.with_name("blah"))

This does not:

bogus_sheet = Sheet.with_name("Unused")
Workbook.append_sheet(%Workbook{sheets: [bogus_sheet]}, Sheet.with_name("blah))

But of course that gives us two sheets.

The problem appears to be in the Workbook module, line 16, which defines sheets as nonempty_list. This makes sense once the sheet is created, but not during creation.

The workaround might be to avoid append_sheet for creation and use %Workbook{sheets: [sheet]} instead.

Suggestion: add a Workbook.new(sheet) function.

Warning if sheet name is too long

If I do

    sheet = %Elixlsx.Sheet{name: "I am a very long sheet name sorry", rows: [[1,2],[1,2]]}
    workbook = %Elixlsx.Workbook{sheets: [sheet]}
    Elixlsx.write_to_memory(workbook, "#file.xlsx")

I got a warning when opening the file in excel (the Data is OK).

Argument Error on write_to_memory

I am trying to take a list of lists and turn it into a spreadsheet
I am doing this by enumerating over everything and putting it into Sheet.set_at/5
Upon calling Workbook.append_sheet(%Workbook{}, worksheet) |> Elixlsx.write_to_memory("filename.xlsx") I get the following

** (ArgumentError) you attempted to apply :rows on {:ok, %Elixlsx.Sheet{col_widths: %{}, group_cols: [], group_rows: [], merge_cells: [], name: "test", pane_freeze: nil, row_heights: %{}, rows: [[["registration", {:bold, true}]], [["C-FUYE"]], [["C-FJXA"]], [["C-LSFR"]], [["C-FUZH"]], [["C-FXPY"]], [["C-DUOD"]], [["C-PRIV"]]], show_grid_lines: true}}. If you are using apply/3, make sure the module is an atom. If you are using the dot syntax, such as map.field or module.function, make sure the left side of the dot is an atom or a map
    :erlang.apply({:ok, %Elixlsx.Sheet{col_widths: %{}, group_cols: [], group_rows: [], merge_cells: [], name: "test", pane_freeze: nil, row_heights: %{}, rows: [[["registration", {:bold, true}]], [["C-FUYE"]], [["C-FJXA"]], [["C-LSFR"]], [["C-FUZH"]], [["C-FXPY"]], [["C-DUOD"]], [["C-PRIV"]]], show_grid_lines: true}}, :rows, [])
    (elixlsx) lib/elixlsx/compiler.ex:68: anonymous fn/2 in Elixlsx.Compiler.compinfo_from_sheets/2
    (elixir) lib/list.ex:228: List."-foldl/3-lists^foldl/2-0-"/3
    (elixlsx) lib/elixlsx/compiler.ex:80: Elixlsx.Compiler.make_workbook_comp_info/1
    (elixlsx) lib/elixlsx.ex:58: Elixlsx.write_to_memory/2

I Have:

  • Elixlsx v0.4.2
  • Elixir v1.9.4
  • Windows 10 (1909)

how do you handle Decimal Data?

Hi, great work on this library.

Please i'm using this to create excel files from a database.

Some of my data contains decimals (via the Elixir Decimal library, e.g. #Decimal<100.25>)

This error comes up:

ERR: %CaseClauseError{term: #Decimal<100.0>}
    (elixlsx) lib/elixlsx/xml_templates.ex:163: Elixlsx.XMLTemplates.get_content_type_value/2
    (elixlsx) lib/elixlsx/xml_templates.ex:197: anonymous fn/3 in Elixlsx.XMLTemplates.xl_sheet_cols/3
    (elixir) lib/enum.ex:1229: Enum."-map/2-lists^map/1-0-"/2
    (elixir) lib/enum.ex:1229: Enum."-map/2-lists^map/1-0-"/2
    (elixlsx) lib/elixlsx/xml_templates.ex:185: Elixlsx.XMLTemplates.xl_sheet_cols/3
    (elixlsx) lib/elixlsx/xml_templates.ex:258: anonymous fn/3 in Elixlsx.XMLTemplates.xl_sheet_rows/3

Please how may we use the Decimal type with elixlsx

Thanks.

xls files returning `nil` for integers

I have two files TestRun.xlsx and TestRun.xls that should return the same.
However xls files are return nil where there should be an integer.

 {:ok, pid, parser} = Exoffice.parse("test/csv_examples/TestRun.xls", 0)
 s = Exoffice.get_rows(pid, parser)
 Enum.map(s, fn(row)-> 
    Enum.map(row, fn(item) -> item end) 
  end)
assert xlsx_sheet_to_list("test/csv_examples/TestRun.xlsx") ===  [
               ["ID", "Thing 1", "Things 2 "],
               [1, "apple ", "blue "],
               [2, "orange", "red"],
               [3, "pear", "green",
               [4, "strawberry", "yellow"],
               [5, "blueberry", "purple"],
               [6, "kiwi", "orange"],
               [7, "lime", "cyan"],
               [8, "lemon", "magenta"]
             ]
assert xls_sheet_to_list("test/csv_examples/TestRun.xls") === [
               ["ID", "Thing 1", "Things 2 "],
               [nil, "apple ", "blue "],
               [nil, "orange", "red"],
               [nil, "pear", "green",
               [nil, "strawberry", "yellow"],
               [nil, "blueberry", "purple"],
               [nil, "kiwi", "orange"],
               [nil, "lime", "cyan"],
               [nil, "lemon", "magenta"]
             ]

If I pass nil into column parameter the lib broke

This code:
%Workbook{sheets: [%Sheet{name: "Posts", rows: [nil]}]} breaks the lib when I execute Elixlsx.write_to_memory("output.xlsx") on Elixlsx.Compiler.compinfo_from_rows.
That's behaviour expected?

Hyperlink support

I need to support hyperlinks. I'm thinking of making a PR for it, but this will probably take a while and I'm not sure how to support cells that contain hyperlinks and normal text at the same time (though I don't personally need it, that seems allowed in the spec).

For anyone looking for a quick fix, you can use the HYPERLINK function like [{:formula, "HYPERLINK(\"#{url}\", \"#{url}\")"}].

So for now I'll just leave this issue here of how they look like in the XLSX:

In the sheet$n.xml row, the hyperlink is referenced via r, like r=C8.
In the sheet$n.xml, in the <workbook/> tag this section:

<hyperlinks>
  <hyperlink ref="C8" r:id="rId1" display="http://example.com"/>
</hyperlinks>

In worksheets/_rels/sheet$n.xml.rels is this content:

<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="http://example.com" TargetMode="External"/>
</Relationships>

I'm not entirely sure how the code for a cell should look like, given that hyperlinks can be mixed with other content.

Is it possible to modify existing file with this library?

Hi!

I love how simple the API in this project is!

I can't find anything about reading xlsx file in the documentation. I am searching for something that can modify existing xlsx file. Is this possible?

Thanks for your amazing work!

0.4.2 release has an XML module defined globally

The 0.4.2 release includes code that defines a top-level XML module (from #86), which causes compilation to fail when loaded in a project that also defines a top-level XML module (or a warning, depending on the setting of --warnings-as-errors).

Usual practice would be to move that module to Elixlsx.XML and add alias lines to the couple of places that use it.

Formula different sheet cell

Hello,

When I try to use a cell of another sheet:

{:formula, "$Deductions.I1"}

The result on the excel cell is the following: =$deductions.i1 and due to the lowercase is not working.

The Workbook seems fine ([formula: "$Deductions.I1", ...]), might be the write_to_memory.

Thank you!

Excel on Mac problem open generated files

When I try to open the generated file(s) using Excel (version 15.32 for Mac) I get a warning/error that the file is broken and that a repair is needed. (See the attached screenshot).

Is this a known problem or something that has never been tested? Any ideas?

screenshot 2017-04-07 11 35 45

Missing newer release tags

Hi, thanks for writing/maintaining this library ✌️

Could you please git push --tags when you have a chance so that the newer releases are tagged appropriately on GitHub? Thanks!

Boolean Value cant convert

Invalid column content at AC11: true

My array may contain boolean value.

Function:

sheet_name =
  "data"
sheet_data =
  %Sheet{name: sheet_name, rows: data}
dir =
  base_dir()
full_path =
  dir <> file_name
{status, _file} =
  %Workbook{sheets: [sheet_data]}
  |> Elixlsx.write_to(full_path)

elixlsx

New release possible?

Hi there and thanks for your work on this library!
Would it be possible to get a release? We currently have lots of warnings in our build logs due to the "old" String.slice syntax you already fixed upstream and we would love to upgrade to a new version.

Thanks again ❤️

Setting "automatic" width of a column

This is more a question or maybe a suggestion for improvement.

Is it possible to set the column width to automatically adapt to the width of the content of the data in the cells? In Excel/LibreOffice you can easily adapt the width by double clicking the resize handle of the column but is there any way to programatically achieve this without a hardcoded width?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.