from tableaudocumentapi.datasource_dependency import DatasourceDependency from tableaudocumentapi.filter import Filter, _parse_filters from tableaudocumentapi.sort import Sort, _parse_sorts from tableaudocumentapi.encoding import Encoding from tableaudocumentapi.utils import _clean_aggregated_column_names import re class Worksheet(object): """A class representing a Worksheet in a Tableau workbook file """ def __init__(self, worksheet_xml): """Initialize the Worksheet from XML element representing it""" self._xml = worksheet_xml self._name = worksheet_xml.attrib['name'] self._datasource_dependencies = self._parse_datasource_dependencies() self._filters = _parse_filters(self._xml, "table/view/filter") self._rows = self._parse_rows_cols('rows') self._cols = self._parse_rows_cols('cols') self._sorts = _parse_sorts(self._xml) self._encodings = self._parse_encodings() self._mark_type = self._parse_mark_type() simple_id = worksheet_xml.find('simple-id') self._id = simple_id.get('uuid', '').replace("{", "").replace("}", "") if simple_id is not None else '' @property def xml(self): """Return the xml of the worksheet""" return self._xml @property def name(self): """Return the name of the worksheet""" return self._name @property def datasource_dependencies(self): """Return the worksheet datsource dependencies""" return self._datasource_dependencies @property def filters(self): """Return the worksheet filters""" return self._filters @property def rows(self): """Return the worksheet rows""" return self._rows @property def cols(self): """Return the worksheet cols""" return self._cols @property def id(self): """Return the worksheet id""" return self._id @property def sorts(self): """Return the worksheet sort specifications.""" return self._sorts @property def encodings(self): """Return all mark encoding specifications across panes.""" return self._encodings @property def mark_type(self): """Return the mark type ('Bar', 'Line', 'Square', 'Automatic', etc.).""" return self._mark_type def _parse_encodings(self): encodings = [] for pane in self._xml.findall('table/panes/pane'): for enc_child in pane.findall('encodings/*'): encodings.append(Encoding(enc_child)) return encodings def _parse_mark_type(self): mark = self._xml.find('table/panes/pane/mark') return mark.get('class') if mark is not None else None def _parse_datasource_dependencies(self): """Function that will parse the datsource dependencies under the worksheet""" datasource_dependencies = [] datasource_dependency_elements = self._xml.findall('table/view/datasource-dependencies') for dependency in datasource_dependency_elements: if dependency.get("datasource"): datasource_dependencies.append(DatasourceDependency(dependency)) return datasource_dependencies def _parse_rows_cols(self, row_or_col): """Function that will parse the rows and columns in the worksheet""" if row_or_col not in ["rows", "cols"]: raise ValueError("row_or_col must be 'rows' or 'cols'") path = f"table/{row_or_col}" # import pdb; pdb.set_trace() text = self._xml.findtext(path, default='').strip() if not text: return [] list_of_rows_cols = [] for _ in text.split(" / "): list_of_rows_cols.append((_)) return list_of_rows_cols