read-excel-file
Version:
Read `.xlsx` files in a web browser or in Node.js
136 lines (135 loc) • 7.83 kB
JavaScript
;
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = parseStyles;
var _excluded = ["xfId"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
/**
* Parses `.xlsx` file styles.
* http://officeopenxml.com/SSstyles.php
* Returns an array of cell styles.
* A cell style index is the cell style ID.
* @param {string} content
* @param {function} parseXml — SAX XML parser.
* @returns {object} styles
*/
function parseStyles(content, parseXml) {
// https://social.msdn.microsoft.com/Forums/sqlserver/en-US/708978af-b598-45c4-a598-d3518a5a09f0/howwhen-is-cellstylexfs-vs-cellxfs-applied-to-a-cell?forum=os_binaryfile
// https://www.office-forums.com/threads/cellxfs-cellstylexfs.2163519/
var state = createInitialState();
return parseXml(content, state, onOpenTag, onCloseTag, null).then(function () {
return getResultFromState(state);
});
function createInitialState() {
return {
numberFormats: [],
baseStyles: [],
// The first `164` elements of the `styles` array are going to be `undefined`
// because those represent the built-in "default" styles in `.xlsx` specification.
// These "default" styles have IDs from `0` to `163`, i.e. according to their index.
styles: [],
cellStyleXfs: false,
cellXfs: false
};
}
function getResultFromState(state) {
return state.styles.map(function (style) {
if (style.xfId) {
var xfId = style.xfId,
styleProperties = _objectWithoutProperties(style, _excluded);
return _objectSpread(_objectSpread({}, state.baseStyles[xfId]), styleProperties);
} else {
return style;
}
});
}
function onOpenTag(tagName, attributes, state) {
if (tagName === 'numFmt') {
// `<numFmts/>` element contains `<numFmt/>` elements.
// `<numFmt/>` defines a "number format" template.
// The value of `numFmtId` attribute is a (numeric) ID of this "number format".
var numFmtId = Number(attributes.numFmtId);
var numberFormat = {
id: numFmtId
};
//
// If (and only if) `numFmtId` is >= 164, it is supposed to specify a `formatCode` (a template).
//
// For some reason, Microsoft Excel 2007 doesn't allow to redefine `numFmtId="99"`
// but at the same time does allow redefining `numFmtId="100"`.
//
// Google AI says:
//
// "Standard built-in Excel formats use IDs from 0 to 49 (and some regional ones up to 81).
// IDs 164 and above are officially reserved for custom formats, but third-party spreadsheet
// generators or older templates frequently assign custom IDs starting at 100 (or lower)"
//
// Because of such "non-strict" behavior of Microsoft Excel 2007 regarding overwriting
// number formats with ID >= 100, this package mimicks such "non-strict" approach.
//
if (numFmtId >= 100) {
numberFormat.template = attributes.formatCode;
}
state.numberFormats[numFmtId] = numberFormat;
} else if (tagName === 'cellStyleXfs') {
// `<cellStyleXfs/>` contains "base styles" that could be extended by `<cellXfs/>`.
// These styles don't apply to individual cells directly. They can only be extended.
state.cellStyleXfs = true;
} else if (tagName === 'cellXfs') {
// `<cellXfs/>` contains individual cell styles. They can extend "base styles".
state.cellXfs = true;
} else if (tagName === 'xf') {
if (state.cellStyleXfs) {
// The index of a `<xf/>` element is by definition its numeric ID.
// Therefore, even empty `style` elements still must be put into the array.
state.baseStyles.push(parseCellStyle(attributes));
} else if (state.cellXfs) {
var style = parseCellStyle(attributes, state.numberFormats);
// A style might extend a "base style" by its numeric ID.
if (attributes.xfId) {
style.xfId = Number(attributes.xfId);
}
// The index of a `<xf/>` element is by definition its numeric ID.
// Therefore, even empty `style` elements still must be put into the array.
state.styles.push(style);
}
}
}
function onCloseTag(tagName, state) {
if (tagName === 'cellStyleXfs') {
state.cellStyleXfs = false;
} else if (tagName === 'cellXfs') {
state.cellXfs = false;
}
}
function parseCellStyle(attributes, numberFormats) {
var style = {};
// `numFmtId` in `<cellStyleXfs/>` and `<cellXfs/>` is a numerical ID
// referencing the cell's "number format". Values from `0` to `163` are built-in formats,
// while values `164` and above are custom formats defined in the `<numFmts/>` element.
if (attributes.numFmtId) {
var numFmtId = Number(attributes.numFmtId);
// Built-in number formats don't have a `<numFmt/>` element in `styles.xml`.
// https://hexdocs.pm/xlsxir/number_styles.html
if (numberFormats && numberFormats[numFmtId]) {
// Non-built-in number format.
style.numberFormat = numberFormats[numFmtId];
} else {
// Built-in number format.
style.numberFormat = {
id: numFmtId
};
}
}
return style;
}
}
//# sourceMappingURL=parseStyles.js.map