_init(workbook, idNode, node, relationshipsNode) {
        if (!node) {
            node = {
                name: "worksheet",
                attributes: {
                    xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
                    'xmlns:r': "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
                    'xmlns:mc': "http://schemas.openxmlformats.org/markup-compatibility/2006",
                    'mc:Ignorable': "x14ac",
                    'xmlns:x14ac': "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"
                },
                children: [{
                    name: "sheetData",
                    attributes: {},
                    children: []
                }]
            };
        }

        this._workbook = workbook;
        this._idNode = idNode;
        this._node = node;
        this._maxSharedFormulaId = -1;
        this._mergeCells = {};
        this._dataValidations = {};
        this._hyperlinks = {};
        this._autoFilter = null;

        // Create the relationships.
        this._relationships = new Relationships(relationshipsNode);

        // Delete the optional dimension node
        xmlq.removeChild(this._node, "dimension");

        // Create the rows.
        this._rows = [];
        this._sheetDataNode = xmlq.findChild(this._node, "sheetData");
        this._sheetDataNode.children.forEach(rowNode => {
            const row = new Row(this, rowNode);
            this._rows[row.rowNumber()] = row;
        });
        this._sheetDataNode.children = this._rows;

        // Create the columns node.
        this._columns = [];
        this._colsNode = xmlq.findChild(this._node, "cols");
        if (this._colsNode) {
            xmlq.removeChild(this._node, this._colsNode);
        } else {
            this._colsNode = { name: 'cols', attributes: {}, children: [] };
        }

        // Cache the col nodes.
        this._colNodes = [];
        _.forEach(this._colsNode.children, colNode => {
            const min = colNode.attributes.min;
            const max = colNode.attributes.max;
            for (let i = min; i <= max; i++) {
                this._colNodes[i] = colNode;
            }
        });

        // Create the sheet properties node.
        this._sheetPrNode = xmlq.findChild(this._node, "sheetPr");
        if (!this._sheetPrNode) {
            this._sheetPrNode = { name: 'sheetPr', attributes: {}, children: [] };
            xmlq.insertInOrder(this._node, this._sheetPrNode, nodeOrder);
        }

        // Create the merge cells.
        this._mergeCellsNode = xmlq.findChild(this._node, "mergeCells");
        if (this._mergeCellsNode) {
            xmlq.removeChild(this._node, this._mergeCellsNode);
        } else {
            this._mergeCellsNode = { name: 'mergeCells', attributes: {}, children: [] };
        }

        const mergeCellNodes = this._mergeCellsNode.children;
        this._mergeCellsNode.children = [];
        mergeCellNodes.forEach(mergeCellNode => {
            this._mergeCells[mergeCellNode.attributes.ref] = mergeCellNode;
        });


        // Create the DataValidations.
        this._dataValidationsNode = xmlq.findChild(this._node, "dataValidations");
        if (this._dataValidationsNode) {
            xmlq.removeChild(this._node, this._dataValidationsNode);
        } else {
            this._dataValidationsNode = { name: 'dataValidations', attributes: {}, children: [] };
        }

        const dataValidationNodes = this._dataValidationsNode.children;
        this._dataValidationsNode.children = [];
        dataValidationNodes.forEach(dataValidationNode => {
            this._dataValidations[dataValidationNode.attributes.sqref] = dataValidationNode;
        });


        // Create the hyperlinks.
        this._hyperlinksNode = xmlq.findChild(this._node, "hyperlinks");
        if (this._hyperlinksNode) {
            xmlq.removeChild(this._node, this._hyperlinksNode);
        } else {
            this._hyperlinksNode = { name: 'hyperlinks', attributes: {}, children: [] };
        }

        const hyperlinkNodes = this._hyperlinksNode.children;
        this._hyperlinksNode.children = [];
        hyperlinkNodes.forEach(hyperlinkNode => {
            this._hyperlinks[hyperlinkNode.attributes.ref] = hyperlinkNode;
        });


        // Create the printOptions.
        this._printOptionsNode = xmlq.findChild(this._node, "printOptions");
        if (this._printOptionsNode) {
            xmlq.removeChild(this._node, this._printOptionsNode);
        } else {
            this._printOptionsNode = { name: 'printOptions', attributes: {}, children: [] };
        }


        // Create the pageMargins.
        this._pageMarginsPresets = {
            normal: {
                left: 0.7,
                right: 0.7,
                top: 0.75,
                bottom: 0.75,
                header: 0.3,
                footer: 0.3
            },
            wide: {
                left: 1,
                right: 1,
                top: 1,
                bottom: 1,
                header: 0.5,
                footer: 0.5
            },
            narrow: {
                left: 0.25,
                right: 0.25,
                top: 0.75,
                bottom: 0.75,
                header: 0.3,
                footer: 0.3
            }
        };
        this._pageMarginsNode = xmlq.findChild(this._node, "pageMargins");
        if (this._pageMarginsNode) {
            // Sheet has page margins, assume preset is template.
            this._pageMarginsPresetName = 'template';

            // Search for a preset that matches existing attributes.
            for (const presetName in this._pageMarginsPresets) {
                if (_.isEqual(this._pageMarginsNode.attributes, this._pageMarginsPresets[presetName])) {
                    this._pageMarginsPresetName = presetName;
                    break;
                }
            }

            // If template preset, then register as template preset, and clear attributes.
            if (this._pageMarginsPresetName === 'template') {
                this._pageMarginsPresets.template = this._pageMarginsNode.attributes;
                this._pageMarginsNode.attributes = {};
            }

            xmlq.removeChild(this._node, this._pageMarginsNode);
        } else {
            // Sheet has no page margins, the preset assignment is therefore undefined.
            this._pageMarginsPresetName = undefined;
            this._pageMarginsNode = { name: 'pageMargins', attributes: {}, children: [] };
        }

        // Create the pageBreaks
        ['colBreaks', 'rowBreaks'].forEach(name => {
            this[`_${name}Node`] = xmlq.findChild(this._node, name);
            if (this[`_${name}Node`]) {
                xmlq.removeChild(this._node, this[`_${name}Node`]);
            } else {
                this[`_${name}Node`] = {
                    name,
                    children: [],
                    attributes: {
                        count: 0,
                        manualBreakCount: 0
                    }
                };
            }
        });
        this._pageBreaks = {
            colBreaks: new PageBreaks(this._colBreaksNode),
            rowBreaks: new PageBreaks(this._rowBreaksNode)
        };
    }
Initializes the sheet.
@param {Workbook} workbook - The parent workbook.
@param {{}} idNode - The sheet ID node (from the parent workbook).
@param {{}} node - The sheet node.
@param {{}} [relationshipsNode] - The optional sheet relationships node.
@returns {undefined}
@private