Source code for spreadsheet_intelligence.parsers.drawing.drawing_element_parser.connector_parser

from warnings import warn
import xml.etree.ElementTree as ET
from spreadsheet_intelligence.models.raw.drawing.drawing_models import (
    ConnectorRaw,
    ConnectorAnchorRaw,
    ArrowLine,
    ArrowHead,
)
from spreadsheet_intelligence.models.raw.drawing.anchor_models import Anchor
from .base_drawing_parser import (
    BaseDrawingParser,
)
from spreadsheet_intelligence.utils.helpers import (
    get_required_attribute,
    get_required_element,
    get_attribute_or_none,
    get_attribute_or_default,
)
from spreadsheet_intelligence.models.common.enums import ConnectorType


[docs] class ConnectorParser(BaseDrawingParser[ConnectorAnchorRaw, ConnectorRaw]): """Parser for the connector element."""
[docs] def parse_line_element(self, line_el: ET.Element) -> ArrowLine: """Parses the <a:ln> element and returns an ArrowLine type. Args: line_el (ET.Element): The <a:ln> element. Returns: ArrowLine: The ArrowLine type. """ # Retrieve basic attributes # There are other attributes in a:ln, but they are not used in this parser. width = int( line_el.get("w", "25400") ) # Default value is 25400 (corresponds to the initial value of 2 pt in Excel) # Retrieve dash style dash_el = line_el.find("a:prstDash", self.namespaces) if dash_el is not None: dash_style = get_required_attribute(dash_el, "val") else: dash_style = "none" # Retrieve arrow settings (stealth, triangle, none) head_end = line_el.find("a:headEnd", self.namespaces) if head_end is not None: head_end_type = get_required_attribute(head_end, "type") else: head_end_type = "none" tail_end = line_el.find("a:tailEnd", self.namespaces) if tail_end is not None: tail_end_type = get_required_attribute(tail_end, "type") else: tail_end_type = "none" return ArrowLine( width=width, dash_style=dash_style, cap=None, # this is not parsed in the current parser compound=None, # this is not parsed in the current parser alignment=None, # this is not parsed in the current parser head=ArrowHead(type=head_end_type, width=None, length=None), tail=ArrowHead(type=tail_end_type, width=None, length=None), )
[docs] def parse_text(self, text_el: ET.Element) -> str: """Parses the <xdr:txBody> element and returns a text string. Args: text_el (ET.Element): The <xdr:txBody> element. Returns: str: The text string. Raises: ValueError: If the text element is not found. TODO: - Text parsing is not implemented when the text contains multiple formats. """ text_element = text_el.find("xdr:txBody/a:p/a:r/a:t", self.namespaces) if text_element is not None and text_element.text is not None: return text_element.text.strip() else: raise ValueError("Text element is not found")
[docs] def _parse_drawing(self, element: ET.Element) -> ConnectorRaw: """Parses the drawing element and returns a ConnectorRaw object. Args: element (ET.Element): The drawing element. Returns: ConnectorRaw: The parsed ConnectorRaw object. """ cxnsp_el = get_required_element(element, "xdr:cxnSp", self.namespaces) id, name = self.parse_info(cxnsp_el, "nvCxnSpPr") prst_geom = get_required_element( cxnsp_el, "xdr:spPr/a:prstGeom", self.namespaces ) connector_type_str = get_required_attribute(prst_geom, "prst") interm_line_pos = None if connector_type_str == "bentConnector3": connector_type = ConnectorType.BENT_CONNECTOR_3 interm_line_el = prst_geom.find("a:avLst/a:gd", self.namespaces) if interm_line_el is not None: interm_line_pos_str = get_required_attribute(interm_line_el, "fmla") interm_line_pos_splt = interm_line_pos_str.split(" ") if len(interm_line_pos_splt) == 2: interm_line_pos = int(interm_line_pos_splt[1]) else: raise ValueError( "Intermediate line position is not valid. Expected format: 'x y'" ) elif connector_type_str == "straightConnector1": connector_type = ConnectorType.STRAIGHT_CONNECTOR_1 else: warn(f"Unsupported connector type: {connector_type_str}") # Parsing the xfrm element xfrm_el = get_required_element(cxnsp_el, "xdr:spPr/a:xfrm", self.namespaces) ext_el = get_required_element(xfrm_el, "a:ext", self.namespaces) off_el = get_required_element(xfrm_el, "a:off", self.namespaces) width = int(get_required_attribute(ext_el, "cx")) height = int(get_required_attribute(ext_el, "cy")) x = int(get_required_attribute(off_el, "x")) y = int(get_required_attribute(off_el, "y")) flip_h = get_attribute_or_none(xfrm_el, "flipH") == "1" flip_v = get_attribute_or_none(xfrm_el, "flipV") == "1" rotation = int(get_attribute_or_default(xfrm_el, "rot", default="0")) # Parsing line line_el = get_required_element(cxnsp_el, "xdr:spPr/a:ln", self.namespaces) arrow_line = self.parse_line_element(line_el) # Style, color scheme_clr, srgb = self.parse_color(line_el) style_refs = self.parse_style_element( get_required_element(cxnsp_el, "xdr:style", self.namespaces) ) return ConnectorRaw( id=id, name=name, connector_type=connector_type, x=x, y=y, width=width, height=height, flip_h=flip_h, flip_v=flip_v, rotation=rotation, arrow_line=arrow_line, interm_line_pos=interm_line_pos, style_refs=style_refs, scheme_clr=scheme_clr, srgb_clr=srgb, )
[docs] def _create_anchor_raw( self, anchor: Anchor, drawing_raw: ConnectorRaw ) -> ConnectorAnchorRaw: """Creates a ConnectorAnchorRaw object. Args: anchor (Anchor): The anchor object. drawing_raw (ConnectorRaw): The drawing raw object. Returns: ConnectorAnchorRaw: The created ConnectorAnchorRaw object. """ return ConnectorAnchorRaw(anchor, drawing_raw)