Upload ods/xlsx
+ Upload ods file
diff --git a/package.json b/package.json
index d1dd7e8..5f5de34 100644
--- a/package.json
+++ b/package.json
@@ -2,8 +2,13 @@
"name": "@odfjs/odfjs",
"version": "0.14.0",
"type": "module",
- "main": "./scripts/node.js",
- "browser": "./scripts/browser.js",
+ "exports": "./exports.js",
+ "imports": {
+ "#DOM": {
+ "node": "./scripts/DOM/node.js",
+ "browser": "./scripts/DOM/browser.js"
+ }
+ },
"scripts": {
"build": "rollup -c",
"dev": "npm-run-all --parallel dev:* start",
diff --git a/readme.md b/readme.md
index 7ef6d19..c099a64 100644
--- a/readme.md
+++ b/readme.md
@@ -6,7 +6,7 @@ Small lib to parse/understand .odf files (.odt, .ods) in the browser and node.js
## Rough roadmap
- [x] add odt templating
-- [ ] remove support for xlsx
+- [x] remove support for xlsx
- [ ] add a .ods minifyer
- [ ] add a generic .ods visualizer
- [ ] move to a dedicated odf docs org
@@ -22,7 +22,7 @@ npm i https://github.com/odfjs/odfjs.git#v0.14.0
```
-### Basic - reading an ods/xlsx file
+### Basic - reading an ods file
```js
import {tableRawContentToObjects, tableWithoutEmptyRows, getODSTableRawContent} from '@odfjs/odfjs'
@@ -40,14 +40,14 @@ async function getFileData(odsFile){
The return value is an array of objects where
the **keys** are the column names in the first row and
-the **values** are automatically converted from the .ods or .xlsx files (which type numbers, strings, booleans and dates)
+the **values** are automatically converted from the .ods files (which type numbers, strings, booleans and dates)
to the appropriate JavaScript value
### Basic - creating an ods file
```js
-import {createOdsFile} from 'ods-xlsx'
+import {createOdsFile} from '@odfjs/odfjs'
const content = new Map([
[
@@ -128,7 +128,7 @@ They can be used to generate lists or tables in .odt files from data and a templ
### Demo
-https://davidbruant.github.io/ods-xlsx/
+https://odfjs.github.io/odfjs/
## Local dev
diff --git a/scripts/App.svelte b/scripts/App.svelte
index eee0e85..5efb86a 100644
--- a/scripts/App.svelte
+++ b/scripts/App.svelte
@@ -1,10 +1,11 @@
-
Import fichier .ods et .xslx
+
Import fichier .ods
Import
diff --git a/scripts/DOM/browser.js b/scripts/DOM/browser.js
new file mode 100644
index 0000000..7b3e57a
--- /dev/null
+++ b/scripts/DOM/browser.js
@@ -0,0 +1,12 @@
+
+console.info('DOM implementation in browser')
+
+/** @type { typeof DOMImplementation.prototype.createDocument } */
+export function createDocument(...args){
+ // @ts-ignore
+ return document.implementation.createDocument(...args)
+}
+
+export const DOMParser = window.DOMParser
+export const XMLSerializer = window.XMLSerializer
+export const Node = window.Node
\ No newline at end of file
diff --git a/scripts/DOM/node.js b/scripts/DOM/node.js
new file mode 100644
index 0000000..5b54354
--- /dev/null
+++ b/scripts/DOM/node.js
@@ -0,0 +1,17 @@
+import { DOMImplementation } from "@xmldom/xmldom"
+
+console.info('DOM implementation in Node.js based on xmldom')
+
+const implementation = new DOMImplementation()
+
+/** @type { typeof DOMImplementation.prototype.createDocument } */
+export function createDocument(...args){
+ // @ts-ignore
+ return implementation.createDocument(...args)
+}
+
+export {
+ DOMParser,
+ XMLSerializer,
+ Node
+} from "@xmldom/xmldom"
\ No newline at end of file
diff --git a/scripts/DOMUtils.js b/scripts/DOMUtils.js
index ff0b1d6..fea84dd 100644
--- a/scripts/DOMUtils.js
+++ b/scripts/DOMUtils.js
@@ -1,8 +1,28 @@
+import {DOMParser, XMLSerializer} from '#DOM'
+
/*
Since we're using xmldom in Node.js context, the entire DOM API is not implemented
Functions here are helpers whild xmldom becomes more complete
*/
+
+/**
+ *
+ * @param {string} str
+ * @returns {Document}
+ */
+export function parseXML(str){
+ return (new DOMParser()).parseFromString(str, 'application/xml');
+}
+
+const serializer = new XMLSerializer()
+
+/** @type { typeof XMLSerializer.prototype.serializeToString } */
+export function serializeToString(node){
+ return serializer.serializeToString(node)
+}
+
+
/**
* Traverses a DOM tree starting from the given element and applies the visit function
* to each Element node encountered in tree order (depth-first).
@@ -21,3 +41,10 @@ export function traverse(node, visit) {
visit(node);
}
+
+export {
+ DOMParser,
+ XMLSerializer,
+ createDocument,
+ Node
+} from '#DOM'
\ No newline at end of file
diff --git a/scripts/browser.js b/scripts/browser.js
deleted file mode 100644
index dc6e03e..0000000
--- a/scripts/browser.js
+++ /dev/null
@@ -1,88 +0,0 @@
-//@ts-check
-
-import {
- _getODSTableRawContent,
- _getXLSXTableRawContent
-} from './shared.js'
-
-import {_createOdsFile} from './createOdsFile.js'
-
-import _fillOdtTemplate from './odf/fillOdtTemplate.js'
-
-
-/** @import {SheetCellRawContent, SheetName, SheetRawContent} from './types.js' */
-/** @import {ODTFile} from './odf/fillOdtTemplate.js' */
-
-
-function parseXML(str){
- return (new DOMParser()).parseFromString(str, 'application/xml');
-}
-
-/**
- * @param {ArrayBuffer} odsArrBuff
- * @returns {ReturnType<_getODSTableRawContent>}
- */
-export function getODSTableRawContent(odsArrBuff){
- return _getODSTableRawContent(odsArrBuff, parseXML)
-}
-
-/**
- * @param {ArrayBuffer} xlsxArrBuff
- * @returns {ReturnType<_getXLSXTableRawContent>}
- */
-export function getXLSXTableRawContent(xlsxArrBuff){
- return _getXLSXTableRawContent(xlsxArrBuff, parseXML)
-}
-
-
-/** @type { typeof DOMImplementation.prototype.createDocument } */
-const createDocument = function createDocument(...args){
- // @ts-ignore
- return document.implementation.createDocument(...args)
-}
-
-const serializer = new XMLSerializer()
-
-/** @type { typeof XMLSerializer.prototype.serializeToString } */
-const serializeToString = function serializeToString(node){
- return serializer.serializeToString(node)
-}
-
-/**
- * @param {ODTFile} odtTemplate
- * @param {any} data
- * @returns {Promise}
- */
-export function fillOdtTemplate(odtTemplate, data){
- return _fillOdtTemplate(odtTemplate, data, parseXML, serializeToString, Node)
-}
-
-
-/**
- * @param {Map} sheetsData
- */
-export function createOdsFile(sheetsData){
- return _createOdsFile(sheetsData, createDocument, serializeToString)
-}
-
-
-export {
- // table-level exports
- tableWithoutEmptyRows,
- tableRawContentToValues,
- tableRawContentToStrings,
- tableRawContentToObjects,
-
- // sheet-level exports
- sheetRawContentToObjects,
- sheetRawContentToStrings,
-
- // row-level exports
- rowRawContentToStrings,
- isRowNotEmpty,
-
- // cell-level exports
- cellRawContentToStrings,
- convertCellValue
-} from './shared.js'
-
diff --git a/scripts/createOdsFile.js b/scripts/createOdsFile.js
index cbd9170..9a014df 100644
--- a/scripts/createOdsFile.js
+++ b/scripts/createOdsFile.js
@@ -1,5 +1,8 @@
import { ZipWriter, BlobWriter, TextReader } from '@zip.js/zip.js';
+import {serializeToString, createDocument} from './DOMUtils.js'
+
+
/** @import {SheetCellRawContent, SheetName, SheetRawContent} from './types.js' */
const stylesXml = `
@@ -22,11 +25,9 @@ const manifestXml = `
/**
* Crée un fichier .ods à partir d'un Map de feuilles de calcul
* @param {Map} sheetsData
- * @param {typeof DOMImplementation.prototype.createDocument} createDocument
- * @param {typeof XMLSerializer.prototype.serializeToString} serializeToString
* @returns {Promise}
*/
-export async function _createOdsFile(sheetsData, createDocument, serializeToString) {
+export async function createOdsFile(sheetsData) {
// Create a new zip writer
const zipWriter = new ZipWriter(new BlobWriter('application/vnd.oasis.opendocument.spreadsheet'));
@@ -44,7 +45,7 @@ export async function _createOdsFile(sheetsData, createDocument, serializeToStri
}
);
- const contentXml = generateContentFileXMLString(sheetsData, createDocument, serializeToString);
+ const contentXml = generateContentFileXMLString(sheetsData);
zipWriter.add("content.xml", new TextReader(contentXml), {level: 9});
zipWriter.add("styles.xml", new TextReader(stylesXml));
@@ -60,11 +61,9 @@ export async function _createOdsFile(sheetsData, createDocument, serializeToStri
/**
* Generate the content.xml file with spreadsheet data
* @param {Map} sheetsData
- * @param {typeof DOMImplementation.prototype.createDocument} createDocument
- * @param {typeof XMLSerializer.prototype.serializeToString} serializeToString
* @returns {string}
*/
-function generateContentFileXMLString(sheetsData, createDocument, serializeToString) {
+function generateContentFileXMLString(sheetsData) {
const doc = createDocument('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'office:document-content');
const root = doc.documentElement;
diff --git a/scripts/node.js b/scripts/node.js
deleted file mode 100644
index ea0dce6..0000000
--- a/scripts/node.js
+++ /dev/null
@@ -1,94 +0,0 @@
-//@ts-check
-
-import {DOMParser, DOMImplementation, XMLSerializer, Node} from '@xmldom/xmldom'
-
-import {
- _getODSTableRawContent,
- _getXLSXTableRawContent
-} from './shared.js'
-import { _createOdsFile } from './createOdsFile.js'
-
-import _fillOdtTemplate from './odf/fillOdtTemplate.js'
-
-/** @import {SheetCellRawContent, SheetName, SheetRawContent} from './types.js' */
-/** @import {ODTFile} from './odf/fillOdtTemplate.js' */
-
-
-/**
- *
- * @param {string} str
- * @returns {Document}
- */
-function parseXML(str){
- return (new DOMParser()).parseFromString(str, 'application/xml');
-}
-
-
-/**
- * @param {ArrayBuffer} odsArrBuff
- * @returns {ReturnType<_getODSTableRawContent>}
- */
-export function getODSTableRawContent(odsArrBuff){
- return _getODSTableRawContent(odsArrBuff, parseXML)
-}
-
-/**
- * @param {ArrayBuffer} xlsxArrBuff
- * @returns {ReturnType<_getXLSXTableRawContent>}
- */
-export function getXLSXTableRawContent(xlsxArrBuff){
- return _getXLSXTableRawContent(xlsxArrBuff, parseXML)
-}
-
-const implementation = new DOMImplementation()
-
-/** @type { typeof DOMImplementation.prototype.createDocument } */
-const createDocument = function createDocument(...args){
- // @ts-ignore
- return implementation.createDocument(...args)
-}
-
-const serializer = new XMLSerializer()
-
-/** @type { typeof XMLSerializer.prototype.serializeToString } */
-const serializeToString = function serializeToString(node){
- return serializer.serializeToString(node)
-}
-
-/**
- * @param {ODTFile} odtTemplate
- * @param {any} data
- * @returns {Promise}
- */
-export function fillOdtTemplate(odtTemplate, data){
- return _fillOdtTemplate(odtTemplate, data, parseXML, serializeToString, Node)
-}
-
-
-/**
- * @param {Map} sheetsData
- */
-export function createOdsFile(sheetsData){
- return _createOdsFile(sheetsData, createDocument, serializeToString)
-}
-
-export {
- // table-level exports
- tableWithoutEmptyRows,
- tableRawContentToValues,
- tableRawContentToStrings,
- tableRawContentToObjects,
-
- // sheet-level exports
- sheetRawContentToObjects,
- sheetRawContentToStrings,
-
- // row-level exports
- rowRawContentToStrings,
- isRowNotEmpty,
-
- // cell-level exports
- cellRawContentToStrings,
- convertCellValue
-} from './shared.js'
-
diff --git a/scripts/odf/fillOdtTemplate.js b/scripts/odf/fillOdtTemplate.js
index c6a7c01..82a9bb1 100644
--- a/scripts/odf/fillOdtTemplate.js
+++ b/scripts/odf/fillOdtTemplate.js
@@ -1,6 +1,6 @@
import { ZipReader, ZipWriter, BlobReader, BlobWriter, TextReader, Uint8ArrayReader, TextWriter, Uint8ArrayWriter } from '@zip.js/zip.js';
-import {traverse} from '../DOMUtils.js'
+import {traverse, parseXML, serializeToString, Node} from '../DOMUtils.js'
import {makeManifestFile, getManifestFileData} from './manifest.js';
/** @import {Reader, ZipWriterAddDataOptions} from '@zip.js/zip.js' */
@@ -344,12 +344,9 @@ function keepFile(filename){
/**
* @param {ODTFile} odtTemplate
* @param {any} data
- * @param {Function} parseXML
- * @param {typeof XMLSerializer.prototype.serializeToString} serializeToString
- * @param {typeof Node} Node
* @returns {Promise}
*/
-export default async function _fillOdtTemplate(odtTemplate, data, parseXML, serializeToString, Node) {
+export default async function fillOdtTemplate(odtTemplate, data) {
const reader = new ZipReader(new Uint8ArrayReader(new Uint8Array(odtTemplate)));
diff --git a/scripts/odf/odt/getOdtTextContent.js b/scripts/odf/odt/getOdtTextContent.js
new file mode 100644
index 0000000..cd468e3
--- /dev/null
+++ b/scripts/odf/odt/getOdtTextContent.js
@@ -0,0 +1,69 @@
+import { ZipReader, Uint8ArrayReader, TextWriter } from '@zip.js/zip.js';
+import {parseXML, Node} from '../../DOMUtils.js'
+
+/** @import {ODTFile} from '../fillOdtTemplate.js' */
+
+/**
+ * @param {ODTFile} odtFile
+ * @returns {Promise}
+ */
+async function getContentDocument(odtFile) {
+ const reader = new ZipReader(new Uint8ArrayReader(new Uint8Array(odtFile)));
+
+ const entries = await reader.getEntries();
+
+ const contentEntry = entries.find(entry => entry.filename === 'content.xml');
+
+ if (!contentEntry) {
+ throw new Error('No content.xml found in the ODT file');
+ }
+
+ // @ts-ignore
+ const contentText = await contentEntry.getData(new TextWriter());
+ await reader.close();
+
+ return parseXML(contentText)
+}
+
+/**
+ *
+ * @param {Document} odtDocument
+ * @returns {Element}
+ */
+function getODTTextElement(odtDocument) {
+ return odtDocument.getElementsByTagName('office:body')[0]
+ .getElementsByTagName('office:text')[0]
+}
+
+/**
+ * Extracts plain text content from an ODT file, preserving line breaks
+ * @param {ArrayBuffer} odtFile - The ODT file as an ArrayBuffer
+ * @returns {Promise} Extracted text content
+ */
+export async function getOdtTextContent(odtFile) {
+ const contentDocument = await getContentDocument(odtFile)
+ const odtTextElement = getODTTextElement(contentDocument)
+
+ /**
+ *
+ * @param {Element} element
+ * @returns {string}
+ */
+ function getElementTextContent(element){
+ //console.log('tagName', element.tagName)
+ if(element.tagName === 'text:h' || element.tagName === 'text:p')
+ return element.textContent + '\n'
+ else{
+ const descendantTexts = Array.from(element.childNodes)
+ .filter(n => n.nodeType === Node.ELEMENT_NODE)
+ .map(getElementTextContent)
+
+ if(element.tagName === 'text:list-item')
+ return `- ${descendantTexts.join('')}`
+
+ return descendantTexts.join('')
+ }
+ }
+
+ return getElementTextContent(odtTextElement)
+}
\ No newline at end of file
diff --git a/scripts/odf/odtTemplate-forNode.js b/scripts/odf/odtTemplate-forNode.js
index e1f19f2..f4cd662 100644
--- a/scripts/odf/odtTemplate-forNode.js
+++ b/scripts/odf/odtTemplate-forNode.js
@@ -1,23 +1,5 @@
import { readFile } from 'node:fs/promises'
-import { ZipReader, Uint8ArrayReader, TextWriter } from '@zip.js/zip.js';
-import {DOMParser, Node} from '@xmldom/xmldom'
-
-
-/** @import {ODTFile} from './fillOdtTemplate.js' */
-
-
-/**
- *
- * @param {Document} odtDocument
- * @returns {Element}
- */
-function getODTTextElement(odtDocument) {
- return odtDocument.getElementsByTagName('office:body')[0]
- .getElementsByTagName('office:text')[0]
-}
-
-
/**
*
* @param {string} path
@@ -27,61 +9,3 @@ export async function getOdtTemplate(path) {
const fileBuffer = await readFile(path)
return fileBuffer.buffer
}
-
-/**
- * Extracts plain text content from an ODT file, preserving line breaks
- * @param {ArrayBuffer} odtFile - The ODT file as an ArrayBuffer
- * @returns {Promise} Extracted text content
- */
-export async function getOdtTextContent(odtFile) {
- const contentDocument = await getContentDocument(odtFile)
- const odtTextElement = getODTTextElement(contentDocument)
-
- /**
- *
- * @param {Element} element
- * @returns {string}
- */
- function getElementTextContent(element){
- //console.log('tagName', element.tagName)
- if(element.tagName === 'text:h' || element.tagName === 'text:p')
- return element.textContent + '\n'
- else{
- const descendantTexts = Array.from(element.childNodes)
- .filter(n => n.nodeType === Node.ELEMENT_NODE)
- .map(getElementTextContent)
-
- if(element.tagName === 'text:list-item')
- return `- ${descendantTexts.join('')}`
-
- return descendantTexts.join('')
- }
- }
-
- return getElementTextContent(odtTextElement)
-}
-
-
-/**
- * @param {ODTFile} odtFile
- * @returns {Promise}
- */
-async function getContentDocument(odtFile) {
- const reader = new ZipReader(new Uint8ArrayReader(new Uint8Array(odtFile)));
-
- const entries = await reader.getEntries();
-
- const contentEntry = entries.find(entry => entry.filename === 'content.xml');
-
- if (!contentEntry) {
- throw new Error('No content.xml found in the ODT file');
- }
-
- // @ts-ignore
- const contentText = await contentEntry.getData(new TextWriter());
- await reader.close();
-
- const parser = new DOMParser();
-
- return parser.parseFromString(contentText, 'text/xml');
-}
\ No newline at end of file
diff --git a/scripts/shared.js b/scripts/shared.js
index 78d89e4..725a80b 100644
--- a/scripts/shared.js
+++ b/scripts/shared.js
@@ -1,6 +1,8 @@
//@ts-check
import { Uint8ArrayReader, ZipReader, TextWriter } from '@zip.js/zip.js';
+import {parseXML} from './DOMUtils.js'
+
/** @import {Entry} from '@zip.js/zip.js'*/
/** @import {SheetName, SheetRawContent, SheetRowRawContent, SheetCellRawContent} from './types.js' */
@@ -46,10 +48,9 @@ function extraxtODSCellText(cell) {
/**
* Extracts raw table content from an ODS file.
* @param {ArrayBuffer} arrayBuffer - The ODS file.
- * @param {(str: string) => Document} parseXML - Function to parse XML content.
* @returns {Promise