diff options
author | chai <chaifix@163.com> | 2021-10-26 11:27:58 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-10-26 11:27:58 +0800 |
commit | 32345800737b668011a87328cd3dcce59ec2934c (patch) | |
tree | e1bbd47ae775f1268447f1c1011ab10492ee9197 | |
parent | ef7aedf5f272c52247d8ee9522d7b2896d21af63 (diff) |
*misc
64 files changed, 2743 insertions, 21 deletions
diff --git a/Editor/EditorApplication.cpp b/Editor/EditorApplication.cpp index 5315e77..f45a2fc 100644 --- a/Editor/EditorApplication.cpp +++ b/Editor/EditorApplication.cpp @@ -16,7 +16,6 @@ EditorApplication::EditorApplication(LuaBind::VM* vm) EditorApplication::~EditorApplication()
{
-
}
void EditorApplication::SetMainWindow(ContainerWindow* wnd)
diff --git a/Editor/Scripting/EditorScripting.cpp b/Editor/Scripting/EditorScripting.cpp index 9cd80cc..ad8ccd6 100644 --- a/Editor/Scripting/EditorScripting.cpp +++ b/Editor/Scripting/EditorScripting.cpp @@ -1,6 +1,8 @@ #include "EditorScripting.h" #include "Runtime/Debug/Log.h" +extern int luaopen_GameLab(lua_State* L); // GameLab + extern int luaopen_GameLab_Debug(lua_State* L); // GameLab.Debug extern int luaopen_GameLab_IO(lua_State* L); // GameLab.IO extern int luaopen_GameLab_Path(lua_State* L); // GameLab.Path @@ -33,6 +35,8 @@ bool SetupGameLabEditorScripting(lua_State* L) { log_info("Scripting", "SetupGameLabEditorScripting()"); + openlib(luaopen_GameLab); + openlib(luaopen_GameLab_Debug); openlib(luaopen_GameLab_Path); openlib(luaopen_GameLab_IO); diff --git a/Projects/VisualStudio/Editor/Editor.vcxproj b/Projects/VisualStudio/Editor/Editor.vcxproj index 48e86e6..39a9cf0 100644 --- a/Projects/VisualStudio/Editor/Editor.vcxproj +++ b/Projects/VisualStudio/Editor/Editor.vcxproj @@ -202,10 +202,12 @@ <ClCompile Include="..\..\..\Runtime\Math\Vector2.cpp" />
<ClCompile Include="..\..\..\Runtime\Math\Vector3.cpp" />
<ClCompile Include="..\..\..\Runtime\Profiling\FrameStats.cpp" />
+ <ClCompile Include="..\..\..\Runtime\Scripting\Common\Common.bind.cpp" />
+ <ClCompile Include="..\..\..\Runtime\Scripting\Common\DataBuffer.bind.cpp" />
<ClCompile Include="..\..\..\Runtime\Scripting\Debug\Debug.bind.cpp" />
<ClCompile Include="..\..\..\Runtime\Scripting\GL\GL.bind.cpp" />
<ClCompile Include="..\..\..\Runtime\Scripting\IO\IO.bind.cpp" />
- <ClCompile Include="..\..\..\Runtime\Scripting\Path.bind.cpp" />
+ <ClCompile Include="..\..\..\Runtime\Scripting\Path\Path.bind.cpp" />
<ClCompile Include="..\..\..\Runtime\Scripting\Rendering\GPUDataBuffer.bind.cpp" />
<ClCompile Include="..\..\..\Runtime\Scripting\Rendering\Rendering.bind.cpp" />
<ClCompile Include="..\..\..\Runtime\Scripting\Rendering\Shader.bind.cpp" />
diff --git a/Projects/VisualStudio/Editor/Editor.vcxproj.filters b/Projects/VisualStudio/Editor/Editor.vcxproj.filters index 30edbd9..29505ea 100644 --- a/Projects/VisualStudio/Editor/Editor.vcxproj.filters +++ b/Projects/VisualStudio/Editor/Editor.vcxproj.filters @@ -100,6 +100,12 @@ <Filter Include="Runtime\Scripting\IO">
<UniqueIdentifier>{350338b7-1176-4edc-9cc7-553a02d69895}</UniqueIdentifier>
</Filter>
+ <Filter Include="Runtime\Scripting\Common">
+ <UniqueIdentifier>{d7f5479d-f669-434b-bb49-ad652755ab89}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Runtime\Scripting\Path">
+ <UniqueIdentifier>{e9a9d1a8-f637-407d-83f7-99dc9da72b8f}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\Editor\GUI\Dock.cpp">
@@ -231,9 +237,6 @@ <ClCompile Include="..\..\..\Runtime\FileSystem\Path.cpp">
<Filter>Runtime\FileSystem</Filter>
</ClCompile>
- <ClCompile Include="..\..\..\Runtime\Scripting\Path.bind.cpp">
- <Filter>Runtime\Scripting</Filter>
- </ClCompile>
<ClCompile Include="..\..\..\Editor\GUI\ContainerWindow.cpp">
<Filter>Editor\GUI</Filter>
</ClCompile>
@@ -324,6 +327,15 @@ <ClCompile Include="..\..\..\Runtime\Scripting\IO\IO.bind.cpp">
<Filter>Runtime\Scripting\IO</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\Runtime\Scripting\Common\Common.bind.cpp">
+ <Filter>Runtime\Scripting\Common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\Runtime\Scripting\Path\Path.bind.cpp">
+ <Filter>Runtime\Scripting\Path</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\Runtime\Scripting\Common\DataBuffer.bind.cpp">
+ <Filter>Runtime\Scripting\Common</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\Editor\GUI\Dock.h">
diff --git a/Resources/Scripts/EditorApplication.lua b/Resources/Scripts/EditorApplication.lua index 10ccbc8..d9f8b1f 100644 --- a/Resources/Scripts/EditorApplication.lua +++ b/Resources/Scripts/EditorApplication.lua @@ -48,15 +48,15 @@ GL.ClearColor({1,1,1,1}) GL.Clear(GL.EBufferType.ColorBuffer) local files = { -"README.txt", -"README.txt", -"README.txt", -"README.txt", -"README.txt", -"README.txt", -"README.txt", -"README.txt", -"README.txt", + "README.txt", + "README.txt", + "README.txt", + "README.txt", + "README.txt", + "README.txt", + "README.txt", + "README.txt", + "README.txt", } GameLab.IO.ReadFilesAsync(files, function() diff --git a/Runtime/Common/DataBuffer.h b/Runtime/Common/DataBuffer.h index 330128f..591fe89 100644 --- a/Runtime/Common/DataBuffer.h +++ b/Runtime/Common/DataBuffer.h @@ -6,9 +6,21 @@ class DataBuffer : public LuaBind::NativeClass<DataBuffer> { public: - DataBuffer(LuaBind::VM* vm); - ~DataBuffer(); + DataBuffer(LuaBind::VM* vm) + :NativeClass<DataBuffer>(vm) + {}; + ~DataBuffer() + { + delete data; + } char* data; int length; + +private: + + LUA_BIND_DECL_CLASS(DataBuffer); + + LUA_BIND_DECL_METHOD(_GetLength); + };
\ No newline at end of file diff --git a/Runtime/FileSystem/File.h b/Runtime/FileSystem/File.h index b0d720c..e64a135 100644 --- a/Runtime/FileSystem/File.h +++ b/Runtime/FileSystem/File.h @@ -6,7 +6,5 @@ class File : public LuaBind::NativeClass<File> public: File(LuaBind::VM* vm); - char* data; - int length; };
\ No newline at end of file diff --git a/Runtime/FileSystem/FileJobs.h b/Runtime/FileSystem/FileJobs.h index 2e53a39..0970c54 100644 --- a/Runtime/FileSystem/FileJobs.h +++ b/Runtime/FileSystem/FileJobs.h @@ -8,7 +8,10 @@ class ReadFilesJob : public Job { public: - ReadFilesJob(LuaBind::VM* vm) : callback(vm), cur(0) {} + ReadFilesJob(LuaBind::VM* vm) + : callback(vm), cur(0) + { + } ~ReadFilesJob() {} void Dispacth(void* param) override; diff --git a/Runtime/FileSystem/Unzip.h b/Runtime/FileSystem/Unzip.h index 45dcbb0..ca38193 100644 --- a/Runtime/FileSystem/Unzip.h +++ b/Runtime/FileSystem/Unzip.h @@ -1,3 +1,10 @@ #pragma once +#include "Runtime/Threading/Job.h" +class UnzipFilesJob : public Job +{ +public: + + +}; diff --git a/Runtime/Lua/LuaBind/LuaBindUtility.h b/Runtime/Lua/LuaBind/LuaBindUtility.h index 7e6eb77..9cc4802 100644 --- a/Runtime/Lua/LuaBind/LuaBindUtility.h +++ b/Runtime/Lua/LuaBind/LuaBindUtility.h @@ -26,8 +26,8 @@ #define LUA_BIND_IMPL_METHOD(type, f) int type::f(lua_State* L) // 由应用程序实现的两个接口。上下文里有一个state。 -#define LUA_BIND_REGISTRY(type) void type::RegisterClass(::State& state) -#define LUA_BIND_POSTPROCESS(type) void type::RegisterPostprocess(::State& state) +#define LUA_BIND_REGISTRY(type) void type::RegisterClass(LuaBind::State& state) +#define LUA_BIND_POSTPROCESS(type) void type::RegisterPostprocess(LuaBind::State& state) // 用来注册的宏。之前这里忘了用可变宏,导致没有luaclastable ref没有注册对。 #define LUA_BIND_REGISTER_CLASS(state, param) state.RegisterNativeClass<param>() diff --git a/Runtime/Scripting/Common/Common.bind.cpp b/Runtime/Scripting/Common/Common.bind.cpp new file mode 100644 index 0000000..081426d --- /dev/null +++ b/Runtime/Scripting/Common/Common.bind.cpp @@ -0,0 +1,14 @@ +#include "Runtime/Lua/LuaHelper.h"
+#include "Runtime/Common/DataBuffer.h"
+
+int luaopen_GameLab(lua_State* L)
+{
+ LUA_BIND_STATE(L);
+
+ state.PushGlobalNamespace();
+ state.PushNamespace("GameLab");
+
+ state.RegisterNativeClass<DataBuffer>();
+
+ return 1;
+}
\ No newline at end of file diff --git a/Runtime/Scripting/Common/DataBuffer.bind.cpp b/Runtime/Scripting/Common/DataBuffer.bind.cpp new file mode 100644 index 0000000..5a5c30a --- /dev/null +++ b/Runtime/Scripting/Common/DataBuffer.bind.cpp @@ -0,0 +1,19 @@ +#include "Runtime/Common/DataBuffer.h"
+
+LUA_BIND_REGISTRY(DataBuffer) +{ + LUA_BIND_REGISTER_METHODS(state, + { "GetLength", _GetLength } + ); +} + +LUA_BIND_POSTPROCESS(DataBuffer) +{
+}
+
+LUA_BIND_IMPL_METHOD(DataBuffer, _GetLength)
+{
+ LUA_BIND_PREPARE(L, DataBuffer);
+ state.Push(self->length);
+ return 1;
+}
\ No newline at end of file diff --git a/Runtime/Scripting/Path.bind.cpp b/Runtime/Scripting/Path/Path.bind.cpp index 920f586..920f586 100644 --- a/Runtime/Scripting/Path.bind.cpp +++ b/Runtime/Scripting/Path/Path.bind.cpp diff --git a/Tools/XlsToCsv/.gitignore b/Tools/XlsToCsv/.gitignore new file mode 100644 index 0000000..7852db8 --- /dev/null +++ b/Tools/XlsToCsv/.gitignore @@ -0,0 +1,46 @@ +*.py[cod] + +# C extensions +*.so + +# Packages +*.egg +*.egg-info +MANIFEST +scripts +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg +lib +lib64 +__pycache__ + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox +nosetests.xml + +# Translations +*.mo + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +*.swp + +# Test +*.csv-test + +# PyCharm +.idea diff --git a/Tools/XlsToCsv/CHANGELOG b/Tools/XlsToCsv/CHANGELOG new file mode 100644 index 0000000..3c586fa --- /dev/null +++ b/Tools/XlsToCsv/CHANGELOG @@ -0,0 +1,97 @@ +version 0.7.9 (2021-Aug-29) + * add support for sheetname argument to convert function + +version 0.7.8 (2021-Apr-19): + * bug fixes + +version 0.7.7 (2020-Jun-23): +version 0.7.6 (2019-Mar-21): + * reverting id field for sheet indexing + +version 0.7.5 (2019-Mar-7): + * Passing "sheets_order" test case. Added support for workbook relations. + * add floadformat to README + * Updated the date formats to current ms excel + * read and use [Content_Types].xml + * Fix for missing cell ids ("r" attribute in <c/>) + * Refactoring, etc. + +version 0.7.4 (2018-Jun-5): + +version 0.7.3 (2017-May-20): + * Support for "xl/worksheets/worksheet.xml" + * Date format "float" leaves value as simple numeric. + * bug fixes by Eudes du Rivau + +version 0.7.2 (2015-Apr-17): + * bug fixes + +version 0.7.1 (2015-Feb-10): + * more date formats + * other fixes + +version 0.7 (2014-Jan-28): + * hyperlinks support + +version 0.6 (2013-Dec-7): + * python 2.4 support + * python 3.3 support + * setuptools + * escape \t\r\n characters option + * bug fixes + +version + * seperate csv files for each sheet (#37) + * #38 issue fix + +version 0.5 (2013-Jun-6): + * Select EOL terminator according to OS (#32) + * floating errors (#28) + * inlineStr support (#24) + * Add man/ directory for manual page (#23) + * Misinterpretation of & (#15) + and other fixes + +version 0.20 (2012-Aug-7) + +version 0.19 (2012-May-17): + * issue #12 fix, some kind of unknown excel app version + +version 0.18 (2012-Feb-19): + * Support for multi-region shared-strings (merge #11) + +version 0.17 (2012-Feb-14): + * issue #10 fix + +version 0.16 (2011-Oct-26): + * new date format + +version 0.15 (2011-Sep-16): + * datetime 1904 format support + * datetime format bug fix + +version 0.14 (2011-jul-15): + * recursively convert the xlsx files in a directory to csv (Zhehao Mao's patch) + +version 0.131 (2011-apr-19): + * skip empty lines option + +version 0.13 (2011-jan-16): + * sheet no bug fix + +version 0.12 (2010-dec-21): + * fix last column empty bug + +version 0.11 (2010-sep-13): + * no numFmt bugfix + +version 0.1 (2010-sep-12): + * better support for date/time formats + * two letter columns bug fixed + * sheets support added + * unicode fix + * boolean type + - thanks to Neil Killeen + +version 0.0 (2010-jun-11): + * xlsx to csv converter first release diff --git a/Tools/XlsToCsv/COPYING b/Tools/XlsToCsv/COPYING new file mode 100644 index 0000000..ecbc059 --- /dev/null +++ b/Tools/XlsToCsv/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License.
\ No newline at end of file diff --git a/Tools/XlsToCsv/LICENSE.txt b/Tools/XlsToCsv/LICENSE.txt new file mode 100644 index 0000000..ecbc059 --- /dev/null +++ b/Tools/XlsToCsv/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License.
\ No newline at end of file diff --git a/Tools/XlsToCsv/MANIFEST.in b/Tools/XlsToCsv/MANIFEST.in new file mode 100644 index 0000000..ad047cc --- /dev/null +++ b/Tools/XlsToCsv/MANIFEST.in @@ -0,0 +1,5 @@ +include test/* +include man/* +include README +include LICENSE.txt +include COPYING diff --git a/Tools/XlsToCsv/README.md b/Tools/XlsToCsv/README.md new file mode 100644 index 0000000..e7bd612 --- /dev/null +++ b/Tools/XlsToCsv/README.md @@ -0,0 +1,119 @@ + +# xlsx2csv + +> xlsx to csv converter (http://github.com/dilshod/xlsx2csv) + +Converts xlsx files to csv format. +Handles large XLSX files. Fast and easy to use. + +## Supported python versions: + - 2.4 + - 2.7 + - 3.4 + +## Installation: + +```sh +sudo easy_install xlsx2csv +``` + or + +```sh +pip install xlsx2csv +``` + + + Also, works standalone with only the *xlsx2csv.py* script + +**Usage:** +``` + xlsx2csv.py [-h] [-v] [-a] [-c OUTPUTENCODING] [-s SHEETID] + [-n SHEETNAME] [-d DELIMITER] [-l LINETERMINATOR] + [-f DATEFORMAT] [--floatformat FLOATFORMAT] + [-i] [-e] [-p SHEETDELIMITER] + [--hyperlinks] + [-I INCLUDE_SHEET_PATTERN [INCLUDE_SHEET_PATTERN ...]] + [-E EXCLUDE_SHEET_PATTERN [EXCLUDE_SHEET_PATTERN ...]] [-m] + xlsxfile [outfile] +``` +**positional arguments:** +``` + xlsxfile xlsx file path + outfile output csv file path, or directory if -s 0 is specified +``` +**optional arguments:** +``` + -h, --help show this help message and exit + -v, --version show program's version number and exit + -a, --all export all sheets + -c OUTPUTENCODING, --outputencoding OUTPUTENCODING + encoding of output csv ** Python 3 only ** (default: utf-8) + -s SHEETID, --sheet SHEETID + sheet number to convert, 0 for all + -n SHEETNAME, --sheetname SHEETNAME + sheet name to convert + -d DELIMITER, --delimiter DELIMITER + delimiter - columns delimiter in csv, 'tab' or 'x09' + for a tab (default: comma ',') + -l LINETERMINATOR, --lineterminator LINETERMINATOR + line terminator - lines terminator in csv, '\n' '\r\n' + or '\r' (default: os.linesep) + -f DATEFORMAT, --dateformat DATEFORMAT + override date/time format (ex. %Y/%m/%d) + --floatformat FLOATFORMAT + override float format (ex. %.15f) + -i, --ignoreempty skip empty lines + -e, --escape Escape \r\n\t characters + -p SHEETDELIMITER, --sheetdelimiter SHEETDELIMITER + sheet delimiter used to separate sheets, pass '' if + you do not need delimiter, or 'x07' or '\\f' for form + feed (default: '--------') + -q QUOTING, --quoting QUOTING + field quoting, 'none' 'minimal' 'nonnumeric' or 'all' (default: 'minimal') + --hyperlinks, --hyperlinks + include hyperlinks + -I INCLUDE_SHEET_PATTERN [INCLUDE_SHEET_PATTERN ...], --include_sheet_pattern INCLUDE_SHEET_PATTERN [INCLUDE_SHEET_PATTERN ...] + only include sheets named matching given pattern, only + effects when -a option is enabled. + -E EXCLUDE_SHEET_PATTERN [EXCLUDE_SHEET_PATTERN ...], --exclude_sheet_pattern EXCLUDE_SHEET_PATTERN [EXCLUDE_SHEET_PATTERN ...] + exclude sheets named matching given pattern, only + effects when -a option is enabled. + -m, --merge-cells merge cells +``` + +Usage from within Python: +``` + from xlsx2csv import Xlsx2csv + Xlsx2csv("myfile.xlsx", outputencoding="utf-8").convert("myfile.csv") +``` + +Expat SAX parser used for xml parsing. + +See alternatives: + +Bash: +http://kirk.webfinish.com/?p=91 + +Python: +http://github.com/staale/python-xlsx +http://github.com/leegao/pyXLSX + +Ruby: +http://roo.rubyforge.org/ + +Java: +http://poi.apache.org/ + + +All programs in this directory and subdirectories are published under +license GNU GPL version 2 or (at your option) any later version. For +more information, see COPYING or visit <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>. + + +## Meta + + Dilshod Temirkhdojaev 鈥 tdilshod@gmail.com + +Distributed under the GNU GENERAL PUBLIC LICENSE. See ``LICENSE`` for more information. + +[https://github.com/dilshod](https://github.com/dilshod) diff --git a/Tools/XlsToCsv/man/Makefile b/Tools/XlsToCsv/man/Makefile new file mode 100644 index 0000000..14afe2a --- /dev/null +++ b/Tools/XlsToCsv/man/Makefile @@ -0,0 +1,14 @@ +# Makefile + +PACKAGE = xlsx2csv + +all: man + +clean: + rm -f *.1 + +man: + + $(MAKE) -f pod2man.mk PACKAGE=$(PACKAGE) makeman + +# End of file diff --git a/Tools/XlsToCsv/man/pod2man.mk b/Tools/XlsToCsv/man/pod2man.mk new file mode 100644 index 0000000..7c114d7 --- /dev/null +++ b/Tools/XlsToCsv/man/pod2man.mk @@ -0,0 +1,71 @@ +# pod2man.mk -- Makefile portion to convert *.pod files to manual pages +# +# Copyright information +# +# Copyright (C) 2008-2012 Jari Aalto +# +# License +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Description +# +# Convert *.pod files to manual pages. Add this to Makefile: +# +# PACKAGE = package +# +# man: +# make -f pod2man.mk PACKAGE=$(PACKAGE) makeman +# +# build: man + +ifneq (,) + This makefile requires GNU Make. +endif + +# This variable *must* be set when called +PACKAGE ?= package + +# Optional variables to set +MANSECT ?= 1 +PODCENTER ?= User Commands +PODDATE ?= $$(date "+%Y-%m-%d") + +# Directories +MANSRC ?= +MANDEST ?= $(MANSRC) + +MANPOD ?= $(MANSRC)$(PACKAGE).$(MANSECT).pod +MANPAGE ?= $(MANDEST)$(PACKAGE).$(MANSECT) + +POD2MAN ?= pod2man +POD2MAN_FLAGS ?= --utf8 + +makeman: $(MANPAGE) + + +$(MANPAGE): $(MANPOD) + # make target - create manual page from a *.pod page + podchecker $(MANPOD) + LC_ALL= LANG=C $(POD2MAN) $(POD2MAN_FLAGS) \ + --center="$(PODCENTER)" \ + --date="$(PODDATE)" \ + --name="$(PACKAGE)" \ + --section="$(MANSECT)" \ + $(MANPOD) \ + | sed 's,[Pp]erl v[0-9.]\+,$(PACKAGE),' \ + > $(MANPAGE) && \ + rm -f pod*.tmp + +# End of of Makefile part diff --git a/Tools/XlsToCsv/man/xlsx2csv.1.pod b/Tools/XlsToCsv/man/xlsx2csv.1.pod new file mode 100644 index 0000000..788f3a8 --- /dev/null +++ b/Tools/XlsToCsv/man/xlsx2csv.1.pod @@ -0,0 +1,120 @@ +# Copyright +# +# Copyright (C) 2011-2012 Jari Aalto +# +# License +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Description +# +# To learn what TOP LEVEL sections to use in manual page, +# see POSIX/Susv standard about "Utility Description Defaults" at +# http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap01.html#tag_01_11 +# +# This manual page in Perl POD format. Read more at +# http://perldoc.perl.org/perlpod.html or run command: +# +# perldoc perlpod | less +# +# To check the syntax: +# +# podchecker *.pod +# +# To create manual: +# +# pod2man PROGRAM.N.pod > PROGRAM.N + +=pod + +=head1 NAME + +xlsx2csv - Convert xlsx xml files to csv format + +=head1 SYNOPSIS + + xlsx2csv [options] INFILE [OUTPUT FILE] + +=head1 DESCRIPTION + +The conversion uses Expat SAX parser for xml processing. + +=head1 OPTIONS + +=over 4 + +=item B<-d DELIMITER, --delimiter=DELIMITER> + +Output csv columns delimiter. Use "tab" or "x09" for +tab. Defaults to comma. + +=item B<-f DATEFORMAT, --dateformat=DATEFORMAT> + +Set date/time format. See strftime(3) for %-format specifiers. An +example "%Y-%m-%d". + +=item B<-i, --ignoreempty> + +Skip empty lines. + +=item B<-p SHEETDELIMITER, --sheetdelimiter=SHEETDELIMITER> + +Sheet delimiter used to separate sheets, pass "" if you don't want +delimiters. DEfaults to "--------". + +=item B<-q QUOTING, --quoting=QUOTING> + +Output csv fields quoting. Use "none" "minimal" "nonnumeric" or "all". +Defaults to none. + +=item B<-r, --recursive> + +Convert recursively. + +=item B<-s SHEETID, --sheet=SHEETID> + +Sheet to convert (0 for all sheets). + +=item B<-h, --help> + +Display short help and exit. + +=item B<--version> + +Display program's version number and exit. + +=back + +=head1 ENVIRONMENT + +None. + +=head1 FILES + +None. + +=head1 SEE ALSO + +catdoc(1) + +=head1 AUTHORS + +Program was written by Dilshod Temirkhodjaev <tdilshod@gmail.com> + +This manual page was written by Jari Aalto <jari.aalto@cante.net>. Released +under license GNU GPL version 2 or (at your option) any later +version. For more information about the license, visit +<http://www.gnu.org/copyleft/gpl.html>. + +=cut diff --git a/Tools/XlsToCsv/setup.py b/Tools/XlsToCsv/setup.py new file mode 100644 index 0000000..fe5ddb7 --- /dev/null +++ b/Tools/XlsToCsv/setup.py @@ -0,0 +1,55 @@ + +import os +import shutil +from distutils.core import setup + +if not os.path.exists('scripts'): + os.makedirs('scripts') +shutil.copyfile('xlsx2csv.py', 'scripts/xlsx2csv') + +scripts = ["scripts/xlsx2csv"] + +name = "xlsx2csv" +version = "0.7.8" +author = "Dilshod Temirkhdojaev" +author_email = "tdilshod@gmail.com" +desc = "xlsx to csv converter" +long_desc = "xlsx to csv converter" +url = "http://github.com/dilshod/xlsx2csv" +classifiers=[ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: End Users/Desktop", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU General Public License (GPL)", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.4", + "Programming Language :: Python :: 2.5", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.0", + "Programming Language :: Python :: 3.1", + "Programming Language :: Python :: 3.2", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Topic :: Office/Business", + "Topic :: Utilities" +] +data_files=[ +] + +setup( + name='xlsx2csv', + version='0.7.8', + description=desc, + author=author, + author_email=author_email, + classifiers=classifiers, + py_modules=['xlsx2csv'], + data_files=data_files, + url=url, + scripts=scripts +) diff --git a/Tools/XlsToCsv/sheets.xlsx b/Tools/XlsToCsv/sheets.xlsx Binary files differnew file mode 100644 index 0000000..70d1a20 --- /dev/null +++ b/Tools/XlsToCsv/sheets.xlsx diff --git a/Tools/XlsToCsv/test/datetime.csv b/Tools/XlsToCsv/test/datetime.csv new file mode 100644 index 0000000..a789017 --- /dev/null +++ b/Tools/XlsToCsv/test/datetime.csv @@ -0,0 +1 @@ +2011-09-15 15:22:00
diff --git a/Tools/XlsToCsv/test/datetime.xlsx b/Tools/XlsToCsv/test/datetime.xlsx Binary files differnew file mode 100644 index 0000000..340fa78 --- /dev/null +++ b/Tools/XlsToCsv/test/datetime.xlsx diff --git a/Tools/XlsToCsv/test/empty_row.csv b/Tools/XlsToCsv/test/empty_row.csv new file mode 100644 index 0000000..9557b99 --- /dev/null +++ b/Tools/XlsToCsv/test/empty_row.csv @@ -0,0 +1,3 @@ +,,,,,,,,,,,, +Date,Agency,Customer,Campaign,Publisher,Format,Inventory,Impressions,Clicks,CTR (%),Price,Price model,Revenue +At the moment no data for report,,,,,,,,,,,, diff --git a/Tools/XlsToCsv/test/empty_row.xlsx b/Tools/XlsToCsv/test/empty_row.xlsx Binary files differnew file mode 100644 index 0000000..fb7e1cf --- /dev/null +++ b/Tools/XlsToCsv/test/empty_row.xlsx diff --git a/Tools/XlsToCsv/test/escape.csv b/Tools/XlsToCsv/test/escape.csv new file mode 100644 index 0000000..a33b914 --- /dev/null +++ b/Tools/XlsToCsv/test/escape.csv @@ -0,0 +1 @@ +,,,,Hello\nWorld\t!,FALSE diff --git a/Tools/XlsToCsv/test/escape.xlsx b/Tools/XlsToCsv/test/escape.xlsx Binary files differnew file mode 100644 index 0000000..57707fe --- /dev/null +++ b/Tools/XlsToCsv/test/escape.xlsx diff --git a/Tools/XlsToCsv/test/float.csv b/Tools/XlsToCsv/test/float.csv new file mode 100644 index 0000000..f0723b1 --- /dev/null +++ b/Tools/XlsToCsv/test/float.csv @@ -0,0 +1,5 @@ + +0.10300 +0.27600 +0.10300 +0.27600 diff --git a/Tools/XlsToCsv/test/float.xlsx b/Tools/XlsToCsv/test/float.xlsx Binary files differnew file mode 100644 index 0000000..9c43167 --- /dev/null +++ b/Tools/XlsToCsv/test/float.xlsx diff --git a/Tools/XlsToCsv/test/hyperlinks.csv b/Tools/XlsToCsv/test/hyperlinks.csv new file mode 100644 index 0000000..4b8aaf7 --- /dev/null +++ b/Tools/XlsToCsv/test/hyperlinks.csv @@ -0,0 +1 @@ +<a href='https://www.google.com/'>google</a>,<a href='https://www.yahoo.com/'>yahoo</a>,<a href='https://www.gmail.com/'>gmail</a>,<a href='http://www.reddit.com/'>reddit</a>,<a href='https://github.com/'>github</a> diff --git a/Tools/XlsToCsv/test/hyperlinks.xlsm b/Tools/XlsToCsv/test/hyperlinks.xlsm Binary files differnew file mode 100644 index 0000000..d028025 --- /dev/null +++ b/Tools/XlsToCsv/test/hyperlinks.xlsm diff --git a/Tools/XlsToCsv/test/hyperlinks_continous.csv b/Tools/XlsToCsv/test/hyperlinks_continous.csv new file mode 100644 index 0000000..81fc63c --- /dev/null +++ b/Tools/XlsToCsv/test/hyperlinks_continous.csv @@ -0,0 +1,18 @@ +<a href='http://google.com/'>google</a>,<a href='http://google.com/'>test</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://reddit.com/'>reddit</a> +<a href='http://google.com/'>google</a>,<a href='http://google.com/'>test</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://reddit.com/'>reddit</a> +<a href='http://google.com/'>google</a>,<a href='http://google.com/'>test</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://reddit.com/'>reddit</a> +<a href='http://google.com/'>google</a>,<a href='http://google.com/'>test</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://reddit.com/'>reddit</a> +<a href='http://google.com/'>google</a>,<a href='http://google.com/'>test</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://reddit.com/'>reddit</a> +<a href='http://google.com/'>google</a>,<a href='http://google.com/'>test</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://reddit.com/'>reddit</a> +<a href='http://google.com/'>google</a>,<a href='http://google.com/'>test</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://reddit.com/'>reddit</a> +<a href='http://google.com/'>google</a>,<a href='http://google.com/'>test</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://reddit.com/'>reddit</a> +<a href='http://google.com/'>google</a>,<a href='http://google.com/'>test</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://reddit.com/'>reddit</a> +<a href='http://reddit.com/'>reddit</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://google.com/'>test</a>,<a href='http://google.com/'>google</a> +<a href='http://reddit.com/'>reddit</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://google.com/'>test</a>,<a href='http://google.com/'>google</a> +<a href='http://reddit.com/'>reddit</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://google.com/'>test</a>,<a href='http://google.com/'>google</a> +<a href='http://reddit.com/'>reddit</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://google.com/'>test</a>,<a href='http://google.com/'>google</a> +<a href='http://reddit.com/'>reddit</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://google.com/'>test</a>,<a href='http://google.com/'>google</a> +<a href='http://reddit.com/'>reddit</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://google.com/'>test</a>,<a href='http://google.com/'>google</a> +<a href='http://reddit.com/'>reddit</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://google.com/'>test</a>,<a href='http://google.com/'>google</a> +<a href='http://reddit.com/'>reddit</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://google.com/'>test</a>,<a href='http://google.com/'>google</a> +<a href='http://reddit.com/'>reddit</a>,<a href='http://yahoo.com/'>yahoo</a>,<a href='http://google.com/'>test</a>,<a href='http://google.com/'>google</a> diff --git a/Tools/XlsToCsv/test/hyperlinks_continous.xlsm b/Tools/XlsToCsv/test/hyperlinks_continous.xlsm Binary files differnew file mode 100644 index 0000000..ddea849 --- /dev/null +++ b/Tools/XlsToCsv/test/hyperlinks_continous.xlsm diff --git a/Tools/XlsToCsv/test/input-weird.csv b/Tools/XlsToCsv/test/input-weird.csv new file mode 100644 index 0000000..bdc150a --- /dev/null +++ b/Tools/XlsToCsv/test/input-weird.csv @@ -0,0 +1,2 @@ +,,, +Some data,,, diff --git a/Tools/XlsToCsv/test/input-weird.xlsx b/Tools/XlsToCsv/test/input-weird.xlsx Binary files differnew file mode 100644 index 0000000..c8f74a2 --- /dev/null +++ b/Tools/XlsToCsv/test/input-weird.xlsx diff --git a/Tools/XlsToCsv/test/junk-small.csv b/Tools/XlsToCsv/test/junk-small.csv new file mode 100644 index 0000000..5212eac --- /dev/null +++ b/Tools/XlsToCsv/test/junk-small.csv @@ -0,0 +1 @@ +29-Mar-1940,25-Jul-2008,08-07-25,08-Apr-2009,test,FALSE
diff --git a/Tools/XlsToCsv/test/junk-small.xlsx b/Tools/XlsToCsv/test/junk-small.xlsx Binary files differnew file mode 100644 index 0000000..ba720df --- /dev/null +++ b/Tools/XlsToCsv/test/junk-small.xlsx diff --git a/Tools/XlsToCsv/test/last-column-empty.csv b/Tools/XlsToCsv/test/last-column-empty.csv new file mode 100644 index 0000000..0b90178 --- /dev/null +++ b/Tools/XlsToCsv/test/last-column-empty.csv @@ -0,0 +1,6 @@ +A,B,C
+stuff,more stuff,
+things,more things,even more things
+a,b,
+one,two,
+1,2,3
diff --git a/Tools/XlsToCsv/test/last-column-empty.xlsx b/Tools/XlsToCsv/test/last-column-empty.xlsx Binary files differnew file mode 100644 index 0000000..4fbaf40 --- /dev/null +++ b/Tools/XlsToCsv/test/last-column-empty.xlsx diff --git a/Tools/XlsToCsv/test/namespace.csv b/Tools/XlsToCsv/test/namespace.csv new file mode 100644 index 0000000..eff7861 --- /dev/null +++ b/Tools/XlsToCsv/test/namespace.csv @@ -0,0 +1,7 @@ +Case # (aka tissue code):,,,,SW101014-03,,,,,,,,,,,+,very light +Injection Site Location (PHAL/CTB):,,,,VISC Visceral Cortex (VISC) encroaching on the Gustatory Cortex (GU),,,,,,,,,,,++,light +Injection Site Location (BDA/FG):,,,,Ssp Primary Somatosensory Cortex (SSp) Layers 4 and 5,,,,,,,,,,,+++,moderate +,,,,,,,,,,,,,,,++++,strong +Summary Notes:,,,,CTb and BDA did not work,,,,,,,,,,,, +Atlas level,Data section (File Name),Data section (LIMS),Anatomical Abbr,Anatomical Structure,PHAL,,,CTB,,,BDA,,,FG,, +,,,,,Contra,Ipsi,Notes,Contra,Ipsi,Notes,Contra,Ipsi,Notes,Contra,Ipsi,Notes diff --git a/Tools/XlsToCsv/test/namespace.xlsx b/Tools/XlsToCsv/test/namespace.xlsx Binary files differnew file mode 100644 index 0000000..4f92bee --- /dev/null +++ b/Tools/XlsToCsv/test/namespace.xlsx diff --git a/Tools/XlsToCsv/test/no_cell_ids.csv b/Tools/XlsToCsv/test/no_cell_ids.csv new file mode 100644 index 0000000..9557b99 --- /dev/null +++ b/Tools/XlsToCsv/test/no_cell_ids.csv @@ -0,0 +1,3 @@ +,,,,,,,,,,,, +Date,Agency,Customer,Campaign,Publisher,Format,Inventory,Impressions,Clicks,CTR (%),Price,Price model,Revenue +At the moment no data for report,,,,,,,,,,,, diff --git a/Tools/XlsToCsv/test/no_cell_ids.xlsx b/Tools/XlsToCsv/test/no_cell_ids.xlsx Binary files differnew file mode 100644 index 0000000..59c3d64 --- /dev/null +++ b/Tools/XlsToCsv/test/no_cell_ids.xlsx diff --git a/Tools/XlsToCsv/test/run b/Tools/XlsToCsv/test/run new file mode 100644 index 0000000..990421c --- /dev/null +++ b/Tools/XlsToCsv/test/run @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import os +import sys +import subprocess +from io import open + +PYTHON_VERSIONS = ["2", "3"] + +""" +This test uses sys.stdout. +That means this test doesn't verify: + - file output process + - differences from sys.stdout like line terminater +""" + +def compare(case, arguments=[]): + failed = False + for pyver in PYTHON_VERSIONS: + ext = "xlsx" + if os.path.exists("test/%s.xlsm" % case): + ext = "xlsm" + + if os.name == 'posix':# in case of Linux + left = subprocess.check_output(["python%s" %pyver, "./xlsx2csv.py"] + arguments + ["test/%s.%s" %(case, ext)]).decode('utf-8').replace('\r','') + elif os.name == 'nt':# in case of Windows + # Use py.exe http://blog.python.org/2011/07/python-launcher-for-windows_11.html on Windows + left = subprocess.check_output(["py", "-%s" %pyver, "./xlsx2csv.py"] + arguments + ["test/%s.%s" %(case, ext)]).decode('utf-8').replace('\r','') + else: + print("os.name is unexpected: "+os.name) + sys.exit(1) + + f = open("test/%s.csv" %case, "r", encoding="utf-8", newline="") + right = f.read().replace('\r','') + f.close() + + if left != right: + print("FAILED: %s %s" %(case, pyver)) + print(" actual:", left.replace("\r", "\\r").replace("\n", "\\n")) + print(" expected:", right.replace("\r", "\\r").replace("\n", "\\n")) + failed = True + else: + print("OK: %s %s" %(case, pyver)) + if failed: + sys.exit(1) + +compare("datetime", ["--dateformat=%Y-%m-%d %H:%M:%S"]) +compare("empty_row") +compare("junk-small") +compare("last-column-empty") +compare("sheets", ["-a"]) +compare("skip_empty_lines", ["-i"]) +compare("twolettercolumns") +compare("xlsx2csv-test-file") +compare("escape", ["-e"]) +compare("hyperlinks", ["--hyperlinks"]) +compare("hyperlinks_continous", ["--hyperlinks"]) +compare("namespace") +compare("float") +compare("variousdelim", ["--all","--sheetdelimiter=x33", "--lineterminator=\\r", "--delimiter=\\t"]) +compare("utf8") +compare("no_cell_ids") +compare("sheets_order", ["-a"]) diff --git a/Tools/XlsToCsv/test/sheets.csv b/Tools/XlsToCsv/test/sheets.csv new file mode 100644 index 0000000..a0fb509 --- /dev/null +++ b/Tools/XlsToCsv/test/sheets.csv @@ -0,0 +1,28 @@ +-------- 1 - 袪械械褋褌褉
+鈩,URL,袧邪蟹胁邪薪懈械,袙械褉.,小芯褋褌.,袗薪邪谢懈褌懈泻,袟邪泻邪蟹褔懈泻
+1,url,<<楔邪斜谢芯薪 褋褑械薪邪褉懈褟>>,1.0,袩芯写锌.,肖邪屑懈谢懈褟 ,肖邪屑懈谢懈褟
+2,,,,,,
+3,,,,,,
+4,,,,,,
+5,,,,,,
+-------- 2 - 袙邪褉懈邪薪褌 懈褋锌芯谢褜蟹芯胁邪薪懈褟
+鈩,协谢械屑械薪褌,袨锌懈褋邪薪懈械,袪械蟹褍谢褜褌邪褌 褕邪谐邪 (袙褘褏芯写),小褋褘谢泻懈
+1,袧芯屑械褉,袩芯谢薪褘泄 泻芯写 (薪芯屑械褉) 褋褑械薪邪褉懈褟,,
+2,袧邪蟹胁邪薪懈械,袩芯谢薪芯械 薪邪蟹胁邪薪懈械 褋褑械薪邪褉懈褟,,
+3,袨锌懈褋邪薪懈械,袣褉邪褌泻芯械 芯锌懈褋邪薪懈械 褋褍褌懈 褋褑械薪邪褉懈褟,,
+4,孝懈锌,孝懈锌 褋褑械薪邪褉懈褟 / 校褉芯胁械薪褜 褋褑械薪邪褉懈褟 - 屑芯卸薪芯 芯锌褍褋褌懈褌褜 懈蟹 芯锌懈褋邪薪懈褟,,
+5,袧邪褋谢械写褍械褌,袣邪泻芯泄 褋褑械薪邪褉懈泄 褟胁谢褟械褌褋褟 褉芯写懈褌械谢褜褋泻懈屑 (斜邪蟹芯胁褘屑) 写谢褟 写邪薪薪芯谐芯 褋褑械薪邪褉懈褟,,
+6.1,袗泻褌械褉 ,袣褌芯 芯褋薪芯胁薪芯械 写械泄褋褌胁褍褞褖械械 谢懈褑芯. 袝褋谢懈 械褋褌褜 械褖械 - 写芯斜邪胁谢褟械屑,,
+6.2,小懈褋褌械屑邪,袣褌芯 芯褋薪芯胁薪芯械 写械泄褋褌胁褍褞褖械械 谢懈褑芯 褋 锌芯蟹懈褑懈懈 褋懈褋褌械屑褘 (锌褉芯写褍泻褌邪). 袝褋谢懈 械褋褌褜 械褖械 - 写芯斜邪胁谢褟械屑,,
+7.1,笑械谢褜,袨写薪邪 懈谢懈 薪械褋泻芯谢褜泻芯 芯锌褉械写械谢械薪薪褘褏 褑械谢械泄 写谢褟 褋褑械薪邪褉懈褟,笑械谢械胁芯泄 锌芯泻邪蟹邪褌械谢褜,
+7.2,笑械谢褜,,,
+7.3,笑械谢褜,,,
+8.1,楔邪谐,袨锌懈褋邪薪懈械 褕邪谐邪 - 泻褌芯 褔褌芯 写械谢邪械褌 / 褋 泻械屑-褔械屑 胁蟹邪懈屑芯写械泄褋褌胁褍械褌,袗褉褌械褎邪泻褌 薪邪 胁褘褏芯写械,
+8.2,楔邪谐,,,
+8.褏,楔邪谐,,,
+9,袗谢褜褌/袠褋泻谢.,薪邪蟹胁邪薪懈械 邪谢褜褌械褉薪邪褌懈胁薪芯谐芯 锌芯褌芯泻邪 / 懈褋泻谢褞褔械薪懈褟,,
+9.1,楔邪谐,,,
+9.褏,楔邪谐,,,
+10,袗谢褜褌/袠褋泻谢.,薪邪蟹胁邪薪懈械 邪谢褜褌械褉薪邪褌懈胁薪芯谐芯 锌芯褌芯泻邪 / 懈褋泻谢褞褔械薪懈褟,,
+10.1,楔邪谐,,,
+10.褏,楔邪谐,,,
diff --git a/Tools/XlsToCsv/test/sheets.xlsx b/Tools/XlsToCsv/test/sheets.xlsx Binary files differnew file mode 100644 index 0000000..70d1a20 --- /dev/null +++ b/Tools/XlsToCsv/test/sheets.xlsx diff --git a/Tools/XlsToCsv/test/sheets_order.csv b/Tools/XlsToCsv/test/sheets_order.csv new file mode 100644 index 0000000..e5820c4 --- /dev/null +++ b/Tools/XlsToCsv/test/sheets_order.csv @@ -0,0 +1,47 @@ +-------- 1 - b +x,y +-10,-1000 +-9,-729 +-8,-512 +-7,-343 +-6,-216 +-5,-125 +-4,-64 +-3,-27 +-2,-8 +-1,-1 +0,0 +1,1 +2,8 +3,27 +4,64 +5,125 +6,216 +7,343 +8,512 +9,729 +10,1000 +11,1331 +12,1728 +13,2197 +14,2744 +-------- 2 - e +EEEEE +EEEE +EEE +EE +E +-------- 3 - d +DDDD +DDD +DD +D +-------- 4 - a +AAAAAAA +AAAA +AAA +AA +AA +AAA +AAAA +AAAAAAA diff --git a/Tools/XlsToCsv/test/sheets_order.xlsx b/Tools/XlsToCsv/test/sheets_order.xlsx Binary files differnew file mode 100644 index 0000000..ba782c3 --- /dev/null +++ b/Tools/XlsToCsv/test/sheets_order.xlsx diff --git a/Tools/XlsToCsv/test/skip_empty_lines.csv b/Tools/XlsToCsv/test/skip_empty_lines.csv new file mode 100644 index 0000000..4362b53 --- /dev/null +++ b/Tools/XlsToCsv/test/skip_empty_lines.csv @@ -0,0 +1,3 @@ +鈩,URL,袧邪蟹胁邪薪懈械,袙械褉.,小芯褋褌.,袗薪邪谢懈褌懈泻,袟邪泻邪蟹褔懈泻
+1,url,<<楔邪斜谢芯薪 褋褑械薪邪褉懈褟>>,1.0,袩芯写锌.,肖邪屑懈谢懈褟 ,肖邪屑懈谢懈褟
+3,,,,,,
diff --git a/Tools/XlsToCsv/test/skip_empty_lines.xlsx b/Tools/XlsToCsv/test/skip_empty_lines.xlsx Binary files differnew file mode 100644 index 0000000..82c6600 --- /dev/null +++ b/Tools/XlsToCsv/test/skip_empty_lines.xlsx diff --git a/Tools/XlsToCsv/test/timeformat.csv b/Tools/XlsToCsv/test/timeformat.csv new file mode 100644 index 0000000..472fd3b --- /dev/null +++ b/Tools/XlsToCsv/test/timeformat.csv @@ -0,0 +1,3 @@ +"03""-""08""-""2017"" ""14:35:00",14:40 +"03""-""08""-""2017"" ""00:00:00",11:30 +"03""-""08""-""2017"" ""15:40:00",00:01 diff --git a/Tools/XlsToCsv/test/timeformat.xlsx b/Tools/XlsToCsv/test/timeformat.xlsx Binary files differnew file mode 100644 index 0000000..4e8f218 --- /dev/null +++ b/Tools/XlsToCsv/test/timeformat.xlsx diff --git a/Tools/XlsToCsv/test/twolettercolumns.csv b/Tools/XlsToCsv/test/twolettercolumns.csv new file mode 100644 index 0000000..c9e3abb --- /dev/null +++ b/Tools/XlsToCsv/test/twolettercolumns.csv @@ -0,0 +1,2 @@ +1,2,3,4,5,6,7,8,9,,,,,,,,,,,,,,,,,10,11,12
+a,b,c,d,e,f,g,,,,,,,,,,,,,,,,,,,h,I,j
diff --git a/Tools/XlsToCsv/test/twolettercolumns.xlsx b/Tools/XlsToCsv/test/twolettercolumns.xlsx Binary files differnew file mode 100644 index 0000000..b25cbff --- /dev/null +++ b/Tools/XlsToCsv/test/twolettercolumns.xlsx diff --git a/Tools/XlsToCsv/test/utf8.csv b/Tools/XlsToCsv/test/utf8.csv new file mode 100644 index 0000000..2b4212b --- /dev/null +++ b/Tools/XlsToCsv/test/utf8.csv @@ -0,0 +1,5 @@ +喔抚喔编釜喔斷傅 喔勦福喔编笟,Thai language +銇撱倱銇仭銇,Japanese language +袟写褉邪胁褋褌胁褍泄褌械,Russian language +啶ㄠぎ啶膏啶む,Hindi +丕賱爻賱丕賲 毓賱賷賰賲,Arabic diff --git a/Tools/XlsToCsv/test/utf8.xlsx b/Tools/XlsToCsv/test/utf8.xlsx Binary files differnew file mode 100644 index 0000000..509d5e4 --- /dev/null +++ b/Tools/XlsToCsv/test/utf8.xlsx diff --git a/Tools/XlsToCsv/test/variousdelim.csv b/Tools/XlsToCsv/test/variousdelim.csv new file mode 100644 index 0000000..10e5ae3 --- /dev/null +++ b/Tools/XlsToCsv/test/variousdelim.csv @@ -0,0 +1 @@ +! 1 - Sheet1
1 2 3
a b c
! 2 - Sheet2
4 5 6
d e f
\ No newline at end of file diff --git a/Tools/XlsToCsv/test/variousdelim.xlsx b/Tools/XlsToCsv/test/variousdelim.xlsx Binary files differnew file mode 100644 index 0000000..fc2382b --- /dev/null +++ b/Tools/XlsToCsv/test/variousdelim.xlsx diff --git a/Tools/XlsToCsv/test/xlsx2csv-test-file.csv b/Tools/XlsToCsv/test/xlsx2csv-test-file.csv new file mode 100644 index 0000000..ec474c4 --- /dev/null +++ b/Tools/XlsToCsv/test/xlsx2csv-test-file.csv @@ -0,0 +1,44 @@ +A,B,C +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +,MSP, +blah,PPS, +blah,PPS, +blah,PPS, +blah,PPS, +blah,PPS, +blah,PPS, +blah,PPS, +blah,PPS, +blah,PPS, +blah,PPS, +blah,PPS, +blah,PPS, diff --git a/Tools/XlsToCsv/test/xlsx2csv-test-file.xlsx b/Tools/XlsToCsv/test/xlsx2csv-test-file.xlsx Binary files differnew file mode 100644 index 0000000..828cfd7 --- /dev/null +++ b/Tools/XlsToCsv/test/xlsx2csv-test-file.xlsx diff --git a/Tools/XlsToCsv/xlsx2csv.py b/Tools/XlsToCsv/xlsx2csv.py new file mode 100644 index 0000000..fe7874b --- /dev/null +++ b/Tools/XlsToCsv/xlsx2csv.py @@ -0,0 +1,1203 @@ +#!/usr/bin/env python +# +# Copyright information +# +# Copyright (C) 2010-2018 Dilshod Temirkhodjaev <tdilshod@gmail.com> +# +# License +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +from __future__ import print_function + +__author__ = "Dilshod Temirkhodjaev <tdilshod@gmail.com>" +__license__ = "GPL-2+" +__version__ = "0.7.9" + +import csv, datetime, zipfile, string, sys, os, re, signal +import xml.parsers.expat +from xml.dom import minidom + +try: + # python2.4 + from cStringIO import StringIO +except: + pass +try: + from argparse import ArgumentParser +except: + # python2.4 + from optparse import OptionParser + +# see also ruby-roo lib at: http://github.com/hmcgowan/roo +FORMATS = { + 'general': 'float', + '0': 'float', + '0.00': 'float', + '#,##0': 'float', + '#,##0.00': 'float', + '0%': 'percentage', + '0.00%': 'percentage', + '0.00e+00': 'float', + 'mm-dd-yy': 'date', + 'd-mmm-yy': 'date', + 'd-mmm': 'date', + 'mmm-yy': 'date', + 'h:mm am/pm': 'date', + 'h:mm:ss am/pm': 'date', + 'h:mm': 'time', + 'h:mm:ss': 'time', + 'm/d/yy h:mm': 'date', + '#,##0 ;(#,##0)': 'float', + '#,##0 ;[red](#,##0)': 'float', + '#,##0.00;(#,##0.00)': 'float', + '#,##0.00;[red](#,##0.00)': 'float', + 'mm:ss': 'time', + '[h]:mm:ss': 'time', + 'mmss.0': 'time', + '##0.0e+0': 'float', + '@': 'float', + 'yyyy\\-mm\\-dd': 'date', + 'dd/mm/yy': 'date', + 'hh:mm:ss': 'time', + "dd/mm/yy\\ hh:mm": 'date', + 'dd/mm/yyyy hh:mm:ss': 'date', + 'yy-mm-dd': 'date', + 'd-mmm-yyyy': 'date', + 'm/d/yy': 'date', + 'm/d/yyyy': 'date', + 'dd-mmm-yyyy': 'date', + 'dd/mm/yyyy': 'date', + 'mm/dd/yy h:mm am/pm': 'date', + 'mm/dd/yy hh:mm': 'date', + 'mm/dd/yyyy h:mm am/pm': 'date', + 'mm/dd/yyyy hh:mm:ss': 'date', + 'yyyy-mm-dd hh:mm:ss': 'date', + '#,##0;(#,##0)': 'float', + '_(* #,##0_);_(* (#,##0);_(* "-"??_);_(@_)': 'float', + '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)': 'float' +} +STANDARD_FORMATS = { + 0: 'general', + 1: '0', + 2: '0.00', + 3: '#,##0', + 4: '#,##0.00', + 9: '0%', + 10: '0.00%', + 11: '0.00e+00', + 12: '# ?/?', + 13: '# ??/??', + 14: 'mm-dd-yy', + 15: 'd-mmm-yy', + 16: 'd-mmm', + 17: 'mmm-yy', + 18: 'h:mm am/pm', + 19: 'h:mm:ss am/pm', + 20: 'h:mm', + 21: 'h:mm:ss', + 22: 'm/d/yy h:mm', + 37: '#,##0 ;(#,##0)', + 38: '#,##0 ;[red](#,##0)', + 39: '#,##0.00;(#,##0.00)', + 40: '#,##0.00;[red](#,##0.00)', + 45: 'mm:ss', + 46: '[h]:mm:ss', + 47: 'mmss.0', + 48: '##0.0e+0', + 49: '@', +} +CONTENT_TYPES = { + 'shared_strings', + 'styles', + 'workbook', + 'worksheet', + 'relationships', +} + +DEFAULT_APP_PATH = "/xl" +DEFAULT_WORKBOOK_PATH = DEFAULT_APP_PATH + "/workbook.xml" + +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + +class XlsxException(Exception): + pass + + +class InvalidXlsxFileException(XlsxException): + pass + + +class SheetNotFoundException(XlsxException): + pass + + +class OutFileAlreadyExistsException(XlsxException): + pass + + +class Xlsx2csv: + """ + Usage: Xlsx2csv("test.xslx", **params).convert("test.csv", sheetid=1) + Input: + xlsxfile - path to file or filehandle + options: + sheetid - sheet no to convert (0 for all sheets) + sheetname - sheet name to convert + dateformat - override date/time format + timeformat - override time format + floatformat - override float format + quoting - if and how to quote + delimiter - csv columns delimiter symbol + sheetdelimiter - sheets delimiter used when processing all sheets + skip_empty_lines - skip empty lines + skip_trailing_columns - skip trailing columns + hyperlinks - include hyperlinks + include_sheet_pattern - only include sheets named matching given pattern + exclude_sheet_pattern - exclude sheets named matching given pattern + exclude_hidden_sheets - exclude hidden sheets + """ + + def __init__(self, xlsxfile, **options): + options.setdefault("delimiter", ",") + options.setdefault("quoting", csv.QUOTE_MINIMAL) + options.setdefault("sheetdelimiter", "--------") + options.setdefault("dateformat", None) + options.setdefault("timeformat", None) + options.setdefault("floatformat", None) + options.setdefault("scifloat", False) + options.setdefault("skip_empty_lines", False) + options.setdefault("skip_trailing_columns", False) + options.setdefault("escape_strings", False) + options.setdefault("no_line_breaks", False) + options.setdefault("hyperlinks", False) + options.setdefault("include_sheet_pattern", ["^.*$"]) + options.setdefault("exclude_sheet_pattern", []) + options.setdefault("exclude_hidden_sheets", False) + options.setdefault("merge_cells", False) + options.setdefault("ignore_formats", ['']) + options.setdefault("lineterminator", "\n") + options.setdefault("outputencoding", "utf-8") + + self.options = options + try: + self.ziphandle = zipfile.ZipFile(xlsxfile) + except (zipfile.BadZipfile, IOError): + raise InvalidXlsxFileException("Invalid xlsx file: " + str(xlsxfile)) + + self.py3 = sys.version_info[0] == 3 + + self.content_types = self._parse(ContentTypes, "/[Content_Types].xml") + self.shared_strings = self._parse(SharedStrings, self.content_types.types["shared_strings"]) + self.styles = self._parse(Styles, self.content_types.types["styles"]) + self.workbook = self._parse(Workbook, self.content_types.types["workbook"]) + workbook_relationships = list(filter(lambda r: "book" in r, self.content_types.types["relationships"]))[0] + self.workbook.relationships = self._parse(Relationships, workbook_relationships) + if self.options['no_line_breaks']: + self.shared_strings.replace_line_breaks() + elif self.options['escape_strings']: + self.shared_strings.escape_strings() + + def __del__(self): + # make sure to close zip file, ziphandler does have a close() method + self.ziphandle.close() + + def getSheetIdByName(self, name): + for s in self.workbook.sheets: + if s['name'] == name: + return s['index'] + return None + + def convert(self, outfile, sheetid=1, sheetname=None): + """outfile - path to file or filehandle""" + if sheetname: + sheetid = self.getSheetIdByName(sheetname) + if not sheetid: + raise XlsxException("Sheet '%s' not found" % sheetname) + if sheetid > 0: + self._convert(sheetid, outfile) + else: + if isinstance(outfile, str): + if not os.path.exists(outfile): + os.makedirs(outfile) + elif os.path.isfile(outfile): + raise OutFileAlreadyExistsException("File " + str(outfile) + " already exists!") + for s in self.workbook.sheets: + sheetname = s['name'] + sheetstate = s['state'] + + # filter hidden sheets + if sheetstate in ('hidden', 'veryHidden') and self.options['exclude_hidden_sheets']: + continue + + # filter sheets by include pattern + include_sheet_pattern = self.options['include_sheet_pattern'] + if type(include_sheet_pattern) == type(""): # optparser lib fix + include_sheet_pattern = [include_sheet_pattern] + if len(include_sheet_pattern) > 0: + include = False + for pattern in include_sheet_pattern: + include = pattern and len(pattern) > 0 and re.match(pattern, sheetname) + if include: + break + if not include: + continue + + # filter sheets by exclude pattern + exclude_sheet_pattern = self.options['exclude_sheet_pattern'] + if type(exclude_sheet_pattern) == type(""): # optparser lib fix + exclude_sheet_pattern = [exclude_sheet_pattern] + exclude = False + for pattern in exclude_sheet_pattern: + exclude = pattern and len(pattern) > 0 and re.match(pattern, sheetname) + if exclude: + break + if exclude: + continue + + if not self.py3: + sheetname = sheetname.encode('utf-8') + of = outfile + if isinstance(outfile, str): + of = os.path.join(outfile, sheetname + '.csv') + elif self.options['sheetdelimiter'] and len(self.options['sheetdelimiter']): + of.write(self.options['sheetdelimiter'] + " " + str(s['index']) + " - " + sheetname + self.options['lineterminator']) + self._convert(s['index'], of) + + def _convert(self, sheet_index, outfile): + closefile = False + if isinstance(outfile, str): + if sys.version_info[0] == 2: + outfile = open(outfile, 'wb+') + elif sys.version_info[0] == 3: + outfile = open(outfile, 'w+', encoding=self.options['outputencoding'], newline="") + else: + sys.stderr.write("error: version of your python is not supported: " + str(sys.version_info) + "\n") + sys.exit(1) + closefile = True + try: + writer = csv.writer(outfile, quoting=self.options['quoting'], delimiter=self.options['delimiter'], + lineterminator=self.options['lineterminator']) + + sheets_filtered = list(filter(lambda s: s['index'] == sheet_index, self.workbook.sheets)) + if len(sheets_filtered) == 0: + eprint("Sheet with index %i not found or can't be handled" % sheet_index) + return 1 + + sheet_path = None + # using sheet relation information + if 'relation_id' in sheets_filtered[0] and sheets_filtered[0]['relation_id'] is not None: + + relation_id = sheets_filtered[0]['relation_id'] + if relation_id in self.workbook.relationships.relationships and \ + 'target' in self.workbook.relationships.relationships[relation_id]: + relationship = self.workbook.relationships.relationships[relation_id] + sheet_path = relationship['target'] + if not (sheet_path.startswith("/xl/") or sheet_path.startswith("xl/")): + sheet_path = "/xl/" + sheet_path + + sheet_file = None + if sheet_path is None: + sheet_path = "/xl/worksheets/sheet%i.xml" % sheet_index + sheet_file = self._filehandle(sheet_path) + if sheet_file is None: + sheet_path = None + if sheet_path is None: + sheet_path = "/xl/worksheets/worksheet%i.xml" % sheet_index + sheet_file = self._filehandle(sheet_path) + if sheet_file is None: + sheet_path = None + if sheet_path is None and sheet_index == 1: + sheet_path = self.content_types.types["worksheet"] + sheet_file = self._filehandle(sheet_path) + if sheet_file is None: + sheet_path = None + if sheet_file is None and sheet_path is not None: + sheet_file = self._filehandle(sheet_path) + if sheet_file is None: + raise SheetNotFoundException("Sheet %i not found" % sheet_index) + sheet = Sheet(self.workbook, self.shared_strings, self.styles, sheet_file) + try: + relationships_path = os.path.join(os.path.dirname(sheet_path), + "_rels", + os.path.basename(sheet_path) + ".rels") + sheet.relationships = self._parse(Relationships, relationships_path) + sheet.set_dateformat(self.options['dateformat']) + sheet.set_timeformat(self.options['timeformat']) + sheet.set_floatformat(self.options['floatformat']) + sheet.set_skip_empty_lines(self.options['skip_empty_lines']) + sheet.set_skip_trailing_columns(self.options['skip_trailing_columns']) + sheet.set_include_hyperlinks(self.options['hyperlinks']) + sheet.set_merge_cells(self.options['merge_cells']) + sheet.set_scifloat(self.options['scifloat']) + sheet.set_ignore_formats(self.options['ignore_formats']) + if self.options['escape_strings'] and sheet.filedata: + sheet.filedata = re.sub(r"(<v>[^<>]+) ([^<>]+</v>)", r"\1\\n\2", + re.sub(r"(<v>[^<>]+)	([^<>]+</v>)", r"\1\\t\2", + re.sub(r"(<v>[^<>]+) ([^<>]+</v>)", r"\1\\r\2", sheet.filedata))) + sheet.to_csv(writer) + finally: + sheet_file.close() + sheet.close() + finally: + if closefile: + outfile.close() + + def _filehandle(self, filename): + for name in filter(lambda f: filename and f.lower() == filename.lower()[1:], self.ziphandle.namelist()): + # python2.4 fix + if not hasattr(self.ziphandle, "open"): + return StringIO(self.ziphandle.read(name)) + return self.ziphandle.open(name, "r") + return None + + def _parse(self, klass, filename): + instance = klass() + filehandle = self._filehandle(filename) + if filehandle: + instance.parse(filehandle) + filehandle.close() + return instance + + +class Workbook: + def __init__(self): + self.sheets = list() + self.date1904 = False + + def parse(self, filehandle): + workbookDoc = minidom.parseString(filehandle.read()) + if workbookDoc.firstChild.namespaceURI: + fileVersion = workbookDoc.firstChild.getElementsByTagNameNS(workbookDoc.firstChild.namespaceURI, + "fileVersion") + else: + fileVersion = workbookDoc.firstChild.getElementsByTagName("fileVersion") + if len(fileVersion) == 0: + self.appName = DEFAULT_APP_PATH + else: + try: + if workbookDoc.firstChild.namespaceURI: + self.appName = \ + workbookDoc.firstChild.getElementsByTagNameNS( + workbookDoc.firstChild.namespaceURI, "fileVersion")[0]._attrs['appName'].value + else: + self.appName = workbookDoc.firstChild.getElementsByTagName("fileVersion")[0]._attrs['appName'].value + except KeyError: + # no app name + self.appName = DEFAULT_APP_PATH + try: + if workbookDoc.firstChild.namespaceURI: + self.date1904 = \ + workbookDoc.firstChild.getElementsByTagNameNS( + workbookDoc.firstChild.namespaceURI, "workbookPr")[0]._attrs['date1904'].value.lower().strip() \ + != "false" + else: + self.date1904 = \ + workbookDoc.firstChild.getElementsByTagName("workbookPr")[0] \ + ._attrs['date1904'].value.lower().strip() \ + != "false" + except: + pass + + if workbookDoc.firstChild.namespaceURI: + sheets = workbookDoc.firstChild.getElementsByTagNameNS(workbookDoc.firstChild.namespaceURI, "sheets")[0] + else: + sheets = workbookDoc.firstChild.getElementsByTagName("sheets")[0] + if workbookDoc.firstChild.namespaceURI: + sheetNodes = sheets.getElementsByTagNameNS(workbookDoc.firstChild.namespaceURI, "sheet") + else: + sheetNodes = sheets.getElementsByTagName("sheet") + for i, sheetNode in enumerate(sheetNodes): + attrs = sheetNode._attrs + name = attrs["name"].value + state = None + if 'state' in attrs: + state = attrs["state"].value + relation_id = None + if 'r:id' in attrs: + relation_id = attrs['r:id'].value + self.sheets.append( + { + 'name': name, + 'relation_id': relation_id, + 'index': i + 1, + 'id': i + 1, # remove id starting 0.8.0 version + 'state': state + } + ) + + +class ContentTypes: + def __init__(self): + self.types = {} + for type in CONTENT_TYPES: + self.types[type] = None + + def parse(self, filehandle): + types = minidom.parseString(filehandle.read()).firstChild + if not types: + return + if types.namespaceURI: + overrideNodes = types.getElementsByTagNameNS(types.namespaceURI, "Override") + else: + overrideNodes = types.getElementsByTagName("Override") + for override in overrideNodes: + attrs = override._attrs + type = attrs.get('ContentType').value + name = attrs.get('PartName').value + if type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": + self.types["workbook"] = name + elif type == "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml": + self.types["styles"] = name + elif type == "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml": + # BUG preserved only last sheet + self.types["worksheet"] = name + elif type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml": + self.types["shared_strings"] = name + elif type == "application/vnd.openxmlformats-package.relationships+xml": + if self.types["relationships"] is None: + self.types["relationships"] = list() + self.types["relationships"].append(name) + + if self.types["workbook"] is None: + self.types["workbook"] = DEFAULT_WORKBOOK_PATH + if self.types["relationships"] is None: + self.types["relationships"] = [os.path.dirname(self.types["workbook"]) + "/_rels/" + \ + os.path.basename(self.types["workbook"]) + ".rels"] + + +class Relationships: + def __init__(self): + self.relationships = {} + + def parse(self, filehandle): + doc = minidom.parseString(filehandle.read()) + if doc.namespaceURI: + relationships = doc.getElementsByTagNameNS(doc.namespaceURI, "Relationships") + else: + relationships = doc.getElementsByTagName("Relationships") + if not relationships: + return + if doc.namespaceURI: + relationshipNodes = relationships[0].getElementsByTagNameNS(doc.namespaceURI, "Relationship") + else: + relationshipNodes = relationships[0].getElementsByTagName("Relationship") + for rel in relationshipNodes: + attrs = rel._attrs + rId = attrs.get('Id') + if rId: + vtype = attrs.get('Type') + target = attrs.get('Target') + self.relationships[str(rId.value)] = { + "type": vtype and str(vtype.value) or None, + "target": target and str(target.value) or None + } + + +class Styles: + def __init__(self): + self.numFmts = {} + self.cellXfs = [] + + def parse(self, filehandle): + styles = minidom.parseString(filehandle.read()).firstChild + # numFmts + if styles.namespaceURI: + numFmtsElement = styles.getElementsByTagNameNS(styles.namespaceURI, "numFmts") + else: + numFmtsElement = styles.getElementsByTagName("numFmts") + if len(numFmtsElement) == 1: + for numFmt in numFmtsElement[0].childNodes: + if numFmt.nodeType == minidom.Node.ELEMENT_NODE: + numFmtId = int(numFmt._attrs['numFmtId'].value) + formatCode = numFmt._attrs['formatCode'].value.lower().replace('\\', '') + self.numFmts[numFmtId] = formatCode + + if styles.namespaceURI: + cellXfsElement = styles.getElementsByTagNameNS(styles.namespaceURI, "cellXfs") + else: + cellXfsElement = styles.getElementsByTagName("cellXfs") + if len(cellXfsElement) == 1: + for cellXfs in cellXfsElement[0].childNodes: + if cellXfs.nodeType != minidom.Node.ELEMENT_NODE or not ( + cellXfs.nodeName == "xf" or cellXfs.nodeName.endswith(":xf")): + continue + if cellXfs._attrs and 'numFmtId' in cellXfs._attrs: + numFmtId = int(cellXfs._attrs['numFmtId'].value) + if self.chk_exists(numFmtId) == None: + numFmtId = int(cellXfs._attrs['applyNumberFormat'].value) + self.cellXfs.append(numFmtId) + else: + self.cellXfs.append(None) + + # When Unknown Numformat ID assign applyNumberFormat + def chk_exists(self, numFmtId): + xfs_numfmt = numFmtId + format_str = None + if xfs_numfmt in self.numFmts: + format_str = self.numFmts[xfs_numfmt] + elif xfs_numfmt in STANDARD_FORMATS: + format_str = STANDARD_FORMATS[xfs_numfmt] + return format_str + + +class SharedStrings: + def __init__(self): + self.parser = None + self.strings = [] + self.si = False + self.t = False + self.rPh = False + self.value = "" + + def parse(self, filehandle): + self.parser = xml.parsers.expat.ParserCreate() + self.parser.CharacterDataHandler = self.handleCharData + self.parser.StartElementHandler = self.handleStartElement + self.parser.EndElementHandler = self.handleEndElement + self.parser.ParseFile(filehandle) + + def escape_strings(self): + for i in range(0, len(self.strings)): + self.strings[i] = self.strings[i].replace("\r", "\\r").replace("\n", "\\n").replace("\t", "\\t") + + def replace_line_breaks(self): + for i in range(0, len(self.strings)): + self.strings[i] = self.strings[i].replace("\r", " ").replace("\n", " ").replace("\t", " ") + + def handleCharData(self, data): + if self.t: + self.value += data + + def handleStartElement(self, name, attrs): + # ignore namespace + i = name.find(":") + if i >= 0: + name = name[i + 1:] + + if name == 'si': + self.si = True + self.value = "" + elif name == 't' and self.rPh: + self.t = False + elif name == 't' and self.si: + self.t = True + elif name == 'rPh': + self.rPh = True + + def handleEndElement(self, name): + # ignore namespace + i = name.find(":") + if i >= 0: + name = name[i + 1:] + + if name == 'si': + self.si = False + self.strings.append(self.value) + elif name == 't': + self.t = False + elif name == 'rPh': + self.rPh = False + + +class Sheet: + def __init__(self, workbook, sharedString, styles, filehandle): + self.py3 = sys.version_info[0] == 3 + self.parser = None + self.writer = None + self.sharedString = None + self.styles = None + self.relationships = None + self.columns_count = -1 + + self.in_sheet = False + self.in_row = False + self.in_cell = False + self.in_cell_value = False + + self.columns = {} + self.lastRowNum = 0 + self.rowNum = None + self.colType = None + self.cellId = None + self.s_attr = None + self.data = None + self.max_columns = -1 + + self.dateformat = None + self.timeformat = "%H:%M" # default time format + self.floatformat = None + self.skip_empty_lines = False + self.skip_trailing_columns = False + + self.filedata = None + self.filehandle = filehandle + self.workbook = workbook + self.sharedStrings = sharedString.strings + self.styles = styles + + self.hyperlinks = {} + self.mergeCells = {} + self.ignore_formats = [] + + self.colIndex = 0 + self.colNum = "" + + def close(self): + # Make sure Worksheet is closed, parsers lib does not have a close() function, so simply delete it + self.parser = None + + def set_dateformat(self, dateformat): + self.dateformat = dateformat + + def set_timeformat(self, timeformat): + if timeformat: + self.timeformat = timeformat + + def set_floatformat(self, floatformat): + self.floatformat = floatformat + + def set_skip_empty_lines(self, skip): + self.skip_empty_lines = skip + + def set_skip_trailing_columns(self, skip): + self.skip_trailing_columns = skip + + def set_ignore_formats(self, ignore_formats): + self.ignore_formats = ignore_formats + + def set_merge_cells(self, mergecells): + if not mergecells: + return + if not self.filedata: + self.filedata = self.filehandle.read() + data = str(self.filedata) # python3: convert byte buffer to string + + # find worksheet tag, we need namespaces from it + start = data.find("<worksheet") + if start < 0: + return + end = data.find(">", start) + worksheet = data[start: end + 1] + + # find hyperlinks part + start = data.find("<mergeCells") + if start < 0: + # hyperlinks not found + return + end = data.find("</mergeCells>") + data = data[start: end + 13] + + # parse hyperlinks + doc = minidom.parseString(worksheet + data + "</worksheet>").firstChild + + if doc.namespaceURI: + mergeCells = doc.getElementsByTagNameNS(doc.namespaceURI, "mergeCell") + else: + mergeCells = doc.getElementsByTagName("mergeCell") + for mergeCell in mergeCells: + attrs = mergeCell._attrs + if 'ref' in attrs.keys(): + rangeStr = attrs['ref'].value + rng = rangeStr.split(":") + if len(rng) > 1: + for cell in self._range(rangeStr): + self.mergeCells[cell] = {} + self.mergeCells[cell]['copyFrom'] = rng[0] + + def set_scifloat(self, scifloat): + self.scifloat = scifloat + + def set_include_hyperlinks(self, hyperlinks): + if not hyperlinks or not self.relationships or not self.relationships.relationships: + return + # we must read file first to get hyperlinks, but we don't wont to parse whole file + if not self.filedata: + self.filedata = self.filehandle.read() + data = str(self.filedata) # python3: convert byte buffer to string + + # find worksheet tag, we need namespaces from it + start = data.find("<worksheet") + if start < 0: + return + end = data.find(">", start) + worksheet = data[start: end + 1] + + # find hyperlinks part + start = data.find("<hyperlinks>") + if start < 0: + # hyperlinks not found + return + end = data.find("</hyperlinks>") + data = data[start: end + 13] + + # parse hyperlinks + doc = minidom.parseString(worksheet + data + "</worksheet>").firstChild + if doc.namespaceURI: + hiperlinkNodes = doc.getElementsByTagNameNS(doc.namespaceURI, "hyperlink") + else: + hiperlinkNodes = doc.getElementsByTagName("hyperlink") + for hlink in hiperlinkNodes: + attrs = hlink._attrs + ref = rId = None + for k in attrs.keys(): + if k == "ref": + ref = str(attrs[k].value) + if k.endswith(":id"): + rId = str(attrs[k].value) + if not ref or not rId: + continue + rel = self.relationships.relationships.get(rId) + if not rel: + continue + target = rel.get('target') + for cell in self._range(ref): + self.hyperlinks[cell] = target + + def to_csv(self, writer): + self.writer = writer + self.parser = xml.parsers.expat.ParserCreate() + self.parser.buffer_text = True + self.parser.CharacterDataHandler = self.handleCharData + self.parser.StartElementHandler = self.handleStartElement + self.parser.EndElementHandler = self.handleEndElement + if self.filedata: + self.parser.Parse(self.filedata) + else: + self.parser.ParseFile(self.filehandle) + + def handleCharData(self, data): + if self.in_cell_value: + format_type = None + format_str = "general" + self.collected_string += data + self.data = self.collected_string + if self.colType == "s": # shared string + format_type = "string" + self.data = self.sharedStrings[int(self.data)] + elif self.colType == "b": # boolean + format_type = "boolean" + self.data = (int(data) == 1 and "TRUE") or (int(data) == 0 and "FALSE") or data + elif self.colType == "str" or self.colType == "inlineStr": + format_type = "string" + self.data = data + elif self.s_attr: + s = int(self.s_attr) + + # get cell format + xfs_numfmt = None + if s < len(self.styles.cellXfs): + xfs_numfmt = self.styles.cellXfs[s] + if xfs_numfmt in self.styles.numFmts: + format_str = self.styles.numFmts[xfs_numfmt] + elif xfs_numfmt in STANDARD_FORMATS: + format_str = STANDARD_FORMATS[xfs_numfmt] + + # get format type + if not format_str: + eprint("unknown format %s at %d" % (format_str, xfs_numfmt)) + return + + if format_str in FORMATS: + format_type = FORMATS[format_str] + elif re.match("^\d+(\.\d+)?$", self.data) and re.match(".*[hsmdyY]", format_str) and not re.match( + '.*\[.*[dmhys].*\]', format_str): + # it must be date format + if float(self.data) < 1: + format_type = "time" + else: + format_type = "date" + elif re.match("^-?\d+(.\d+)?$", self.data) or ( + self.scifloat and re.match("^-?\d+(.\d+)?([eE]-?\d+)?$", self.data)): + format_type = "float" + if format_type == 'date' and self.dateformat == 'float': + format_type = "float" + elif self.colType == "n": + format_type = "float" + + if format_type and not format_type in self.ignore_formats: + try: + if format_type == 'date': # date/time + if self.workbook.date1904: + date = datetime.datetime(1904, 1, 1) + datetime.timedelta(float(self.data)) + else: + date = datetime.datetime(1899, 12, 30) + datetime.timedelta(float(self.data)) + if self.dateformat: + # str(dateformat) - python2.5 bug, see: http://bugs.python.org/issue2782 + self.data = date.strftime(str(self.dateformat)) + else: + # ignore ";@", don't know what does it mean right now + # ignore "[$-409], [$-f409], [$-16001]" and similar format codes + dateformat = re.sub(r"\[\$\-[A-z0-9]*\]", "", format_str, 1) \ + .replace(";@", "").replace("yyyy", "%Y").replace("yy", "%y") \ + .replace("hh:mm", "%H:%M").replace("h", "%I").replace("%H%H", "%H") \ + .replace("ss", "%S").replace("dddd", "d").replace("dd", "d").replace("d", "%d") \ + .replace("am/pm", "%p").replace("mmmm", "%B").replace("mmm", "%b") \ + .replace(":mm", ":%M").replace("m", "%m").replace("%m%m", "%m") + self.data = date.strftime(str(dateformat)).strip() + elif format_type == 'time': # time + t = int(round((float(self.data) % 1) * 24 * 60 * 60, 6)) # it should be in seconds + d = datetime.time(int((t // 3600) % 24), int((t // 60) % 60), int(t % 60)) + self.data = d.strftime(self.timeformat) + elif format_type == 'float' and ('E' in self.data or 'e' in self.data): + self.data = str(self.floatformat or '%f') % float(self.data) + # if cell is general, be aggressive about stripping any trailing 0s, decimal points, etc. + elif format_type == 'float' and format_str == 'general': + self.data = ("%f" % (float(self.data))).rstrip('0').rstrip('.') + elif format_type == 'float' and format_str[0:3] == '0.0': + if self.floatformat: + self.data = str(self.floatformat) % float(self.data) + else: + L = len(format_str.split(".")[1]) + if '%' in format_str: + L += 1 + self.data = ("%." + str(L) + "f") % float(self.data) + elif format_type == 'float': + # unsupported float formatting + self.data = ("%f" % (float(self.data))).rstrip('0').rstrip('.') + + except (ValueError, OverflowError): # this catch must be removed, it's hiding potential problems + eprint("Error: potential invalid date format.") + # invalid date format + pass + + def handleStartElement(self, name, attrs): + has_namespace = name.find(":") > 0 + if self.in_row and (name == 'c' or (has_namespace and name.endswith(':c'))): + self.colType = attrs.get("t") + self.s_attr = attrs.get("s") + self.cellId = attrs.get("r") + if self.cellId: + self.colNum = self.cellId[:len(self.cellId) - len(self.rowNum)] + self.colIndex = 0 + else: + self.colIndex += 1 + self.data = "" + self.in_cell = True + elif self.in_cell and ( + (name == 'v' or name == 'is') or (has_namespace and (name.endswith(':v') or name.endswith(':is')))): + self.in_cell_value = True + self.collected_string = "" + elif self.in_sheet and (name == 'row' or (has_namespace and name.endswith(':row'))) and ('r' in attrs): + self.rowNum = attrs['r'] + self.in_row = True + self.colIndex = 0 + self.colNum = "" + self.columns = {} + self.spans = None + if 'spans' in attrs: + self.spans = [int(i) for i in attrs['spans'].split(" ")[-1].split(":")] + elif name == 't': + # reset collected string + self.collected_string = "" + + elif name == 'sheetData' or (has_namespace and name.endswith(':sheetData')): + self.in_sheet = True + elif name == 'dimension': + rng = attrs.get("ref").split(":") + if len(rng) > 1: + start = re.match("^([A-Z]+)(\d+)$", rng[0]) + if (start): + end = re.match("^([A-Z]+)(\d+)$", rng[1]) + startCol = start.group(1) + endCol = end.group(1) + self.columns_count = 0 + for cell in self._range(startCol + "1:" + endCol + "1"): + self.columns_count += 1 + + def handleEndElement(self, name): + has_namespace = name.find(":") > 0 + if self.in_cell and ((name == 'v' or name == 'is' or name == 't') or ( + has_namespace and (name.endswith(':v') or name.endswith(':is')))): + self.in_cell_value = False + elif self.in_cell and (name == 'c' or (has_namespace and name.endswith(':c'))): + t = 0 + for i in self.colNum: t = t * 26 + ord(i) - 64 + d = self.data + if self.hyperlinks: + hyperlink = self.hyperlinks.get(self.cellId) + if hyperlink: + d = "<a href='" + hyperlink + "'>" + d + "</a>" + if self.colNum + self.rowNum in self.mergeCells.keys(): + if 'copyFrom' in self.mergeCells[self.colNum + self.rowNum].keys() and \ + self.mergeCells[self.colNum + self.rowNum]['copyFrom'] == self.colNum + self.rowNum: + self.mergeCells[self.colNum + self.rowNum]['value'] = d + else: + d = self.mergeCells[self.mergeCells[self.colNum + self.rowNum]['copyFrom']]['value'] + + self.columns[t - 1 + self.colIndex] = d + + if self.in_row and (name == 'row' or (has_namespace and name.endswith(':row'))): + if len(self.columns.keys()) > 0: + if min(self.columns.keys()) < 0: # Weird + d = [] + keys = self.columns.keys() + keys.sort() + for k in keys: + val = self.columns[k] + if not self.py3: + val = val.encode("utf-8") + d.append(val) + else: + d = [""] * (max(self.columns.keys()) + 1) + for k in self.columns.keys(): + val = self.columns[k] + if not self.py3: + val = val.encode("utf-8") + d[k] = val + if self.spans: + l = self.spans[1] + if len(d) < l: + d += (l - len(d)) * [''] + + # write empty lines + if not self.skip_empty_lines: + for i in range(self.lastRowNum, int(self.rowNum) - 1): + self.writer.writerow([]) + self.lastRowNum = int(self.rowNum) + + # write line to csv + if not self.skip_empty_lines or d.count('') != len(d): + while len(d) < self.columns_count: + d.append("") + + if self.skip_trailing_columns: + if self.max_columns < 0: + self.max_columns = len(d) + while len(d) > 0 and d[-1] == "": + d = d[0:-1] + self.max_columns = self.max_columns - 1 + elif self.max_columns > 0: + d = d[0:self.max_columns] + self.writer.writerow(d) + + self.in_row = False + elif self.in_sheet and (name == 'sheetData' or (has_namespace and name.endswith(':sheetData'))): + self.in_sheet = False + + # rangeStr: "A3:C12" or "D5" + # example: for cell in _range("A1:Z12"): print cell + def _range(self, rangeStr): + rng = rangeStr.split(":") + if len(rng) == 1: + yield rangeStr + else: + start = re.match("^([A-Z]+)(\d+)$", rng[0]) + end = re.match("^([A-Z]+)(\d+)$", rng[1]) + if not start or not end: + return + startCol = start.group(1) + startRow = int(start.group(2)) + endCol = end.group(1) + endRow = int(end.group(2)) + col = startCol + while True: + for row in range(startRow, endRow + 1): + yield col + str(row) + if col == endCol: + break + t = 0 + for i in col: t = t * 26 + ord(i) - 64 + col = "" + while t >= 0: + col = chr(t % 26 + 65) + col + t = t // 26 - 1 + + +def convert_recursive(path, sheetid, outfile, kwargs): + for name in os.listdir(path): + fullpath = os.path.join(path, name) + if os.path.isdir(fullpath): + convert_recursive(fullpath, sheetid, outfile, kwargs) + else: + outfilepath = outfile + if len(outfilepath) == 0 and fullpath.lower().endswith(".xlsx"): + outfilepath = fullpath[:-4] + 'csv' + + print("Converting %s to %s" % (fullpath, outfilepath)) + try: + Xlsx2csv(fullpath, **kwargs).convert(outfilepath, sheetid) + except zipfile.BadZipfile: + print("File %s is not a zip file" % fullpath) + + +if __name__ == "__main__": + try: + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + signal.signal(signal.SIGINT, signal.SIG_DFL) + except AttributeError: + pass + + if "ArgumentParser" in globals(): + parser = ArgumentParser(description="xlsx to csv converter") + parser.add_argument('infile', metavar='xlsxfile', help="xlsx file path") + parser.add_argument('outfile', metavar='outfile', nargs='?', help="output csv file path") + parser.add_argument('-v', '--version', action='version', version=__version__) + nargs_plus = "+" + argparser = True + else: + parser = OptionParser(usage="%prog [options] infile [outfile]", version=__version__) + parser.add_argument = parser.add_option + nargs_plus = 1 + argparser = False + + if sys.version_info[0] == 2 and sys.version_info[1] < 5: + inttype = "int" + else: + inttype = int + parser.add_argument("-a", "--all", dest="all", default=False, action="store_true", + help="export all sheets") + parser.add_argument("-c", "--outputencoding", dest="outputencoding", default="utf-8", action="store", + help="encoding of output csv ** Python 3 only ** (default: utf-8)") + parser.add_argument("-d", "--delimiter", dest="delimiter", default=",", + help="delimiter - columns delimiter in csv, 'tab' or 'x09' for a tab (default: comma ',')") + parser.add_argument("--hyperlinks", "--hyperlinks", dest="hyperlinks", action="store_true", default=False, + help="include hyperlinks") + parser.add_argument("-e", "--escape", dest='escape_strings', default=False, action="store_true", + help="Escape \\r\\n\\t characters") + parser.add_argument("--no-line-breaks", "--no-line-breaks", dest='no_line_breaks', default=False, action="store_true", + help="Replace \\r\\n\\t with space") + parser.add_argument("-E", "--exclude_sheet_pattern", nargs=nargs_plus, dest="exclude_sheet_pattern", default="", + help="exclude sheets named matching given pattern, only effects when -a option is enabled.") + parser.add_argument("-f", "--dateformat", dest="dateformat", + help="override date/time format (ex. %%Y/%%m/%%d)") + parser.add_argument("-t", "--timeformat", dest="timeformat", + help="override time format (ex. %%H/%%M/%%S)") + parser.add_argument("--floatformat", dest="floatformat", + help="override float format (ex. %%.15f)") + parser.add_argument("--sci-float", dest="scifloat", default=False, action="store_true", + help="force scientific notation to float") + parser.add_argument("-I", "--include_sheet_pattern", nargs=nargs_plus, dest="include_sheet_pattern", default="^.*$", + help="only include sheets named matching given pattern, only effects when -a option is enabled.") + parser.add_argument("--exclude_hidden_sheets", default=False, action="store_true", + help="Exclude hidden sheets from the output, only effects when -a option is enabled.") + parser.add_argument("--ignore-formats", nargs=nargs_plus, type=str, dest="ignore_formats", default=[''], + help="Ignores format for specific data types.") + parser.add_argument("-l", "--lineterminator", dest="lineterminator", default="\n", + help="line terminator - lines terminator in csv, '\\n' '\\r\\n' or '\\r' (default: \\n)") + parser.add_argument("-m", "--merge-cells", dest="merge_cells", default=False, action="store_true", + help="merge cells") + parser.add_argument("-n", "--sheetname", dest="sheetname", default=None, + help="sheet name to convert") + parser.add_argument("-i", "--ignoreempty", dest="skip_empty_lines", default=False, action="store_true", + help="skip empty lines") + parser.add_argument("--skipemptycolumns", dest="skip_trailing_columns", default=False, action="store_true", + help="skip trailing empty columns") + parser.add_argument("-p", "--sheetdelimiter", dest="sheetdelimiter", default="--------", + help="sheet delimiter used to separate sheets, pass '' if you do not need delimiter, or 'x07' " + "or '\\f' for form feed (default: '--------')") + parser.add_argument("-q", "--quoting", dest="quoting", default="minimal", + help="quoting - fields quoting in csv, 'none' 'minimal' 'nonnumeric' or 'all' (default: minimal)") + parser.add_argument("-s", "--sheet", dest="sheetid", default=1, type=inttype, + help="sheet number to convert") + + if argparser: + options = parser.parse_args() + else: + (options, args) = parser.parse_args() + if len(args) < 1: + parser.print_usage() + sys.stderr.write("error: too few arguments" + os.linesep) + sys.exit(1) + options.infile = args[0] + options.outfile = len(args) > 1 and args[1] or None + + if len(options.delimiter) == 1: + pass + elif options.delimiter == 'tab' or options.delimiter == '\\t': + options.delimiter = '\t' + elif options.delimiter == 'comma': + options.delimiter = ',' + elif options.delimiter[0] == 'x': + options.delimiter = chr(int(options.delimiter[1:])) + else: + sys.stderr.write("error: invalid delimiter\n") + sys.exit(1) + + if options.quoting == 'none': + options.quoting = csv.QUOTE_NONE + elif options.quoting == 'minimal': + options.quoting = csv.QUOTE_MINIMAL + elif options.quoting == 'nonnumeric': + options.quoting = csv.QUOTE_NONNUMERIC + elif options.quoting == 'all': + options.quoting = csv.QUOTE_ALL + else: + sys.stderr.write("error: invalid quoting\n") + sys.exit(1) + + if options.lineterminator == '\n': + pass + elif options.lineterminator == '\\n': + options.lineterminator = '\n' + elif options.lineterminator == '\\r': + options.lineterminator = '\r' + elif options.lineterminator == '\\r\\n': + options.lineterminator = '\r\n' + else: + sys.stderr.write("error: invalid line terminator\n") + sys.exit(1) + + if options.sheetdelimiter == '--------': + pass + elif options.sheetdelimiter == '': + pass + elif options.sheetdelimiter == '\\f': + options.sheetdelimiter = '\f' + elif options.sheetdelimiter[0] == 'x': + options.sheetdelimiter = chr(int(options.sheetdelimiter[1:])) + else: + sys.stderr.write("error: invalid sheet delimiter\n") + sys.exit(1) + + kwargs = { + 'delimiter': options.delimiter, + 'quoting': options.quoting, + 'sheetdelimiter': options.sheetdelimiter, + 'dateformat': options.dateformat, + 'timeformat': options.timeformat, + 'floatformat': options.floatformat, + 'scifloat': options.scifloat, + 'skip_empty_lines': options.skip_empty_lines, + 'skip_trailing_columns': options.skip_trailing_columns, + 'escape_strings': options.escape_strings, + 'no_line_breaks': options.no_line_breaks, + 'hyperlinks': options.hyperlinks, + 'include_sheet_pattern': options.include_sheet_pattern, + 'exclude_sheet_pattern': options.exclude_sheet_pattern, + 'exclude_hidden_sheets': options.exclude_hidden_sheets, + 'merge_cells': options.merge_cells, + 'outputencoding': options.outputencoding, + 'lineterminator': options.lineterminator, + 'ignore_formats': options.ignore_formats + } + sheetid = options.sheetid + if options.all: + sheetid = 0 + + outfile = options.outfile or sys.stdout + try: + if os.path.isdir(options.infile): + convert_recursive(options.infile, sheetid, outfile, kwargs) + else: + xlsx2csv = Xlsx2csv(options.infile, **kwargs) + if options.sheetname: + sheetid = xlsx2csv.getSheetIdByName(options.sheetname) + if not sheetid: + raise XlsxException("Sheet '%s' not found" % options.sheetname) + xlsx2csv.convert(outfile, sheetid) + except XlsxException: + _, e, _ = sys.exc_info() + sys.stderr.write(str(e) + "\n") + sys.exit(1) |