""" 模板系统模块 管理可复用的幻灯片布局和变量解析。 """ import re from pathlib import Path from loaders.yaml_loader import YAMLError, load_yaml_file, validate_template_yaml class Template: """模板类,管理可复用的幻灯片布局""" def __init__(self, template_file, templates_dir=None): """ 初始化模板 Args: template_file: 模板名称(纯文件名,不含路径) templates_dir: 模板文件目录 """ # 检查是否提供了 templates_dir if templates_dir is None: raise YAMLError( f"未指定模板目录,无法加载模板: {template_file}\n" f"请使用 --template-dir 参数指定模板目录" ) # 验证模板名称(不能包含路径分隔符) if '/' in template_file or '\\' in template_file: raise YAMLError( f"模板名称不能包含路径分隔符: {template_file}\n" f"模板名称应该是纯文件名,如: 'title-slide'" ) # 构建模板路径 template_path = Path(templates_dir) / f"{template_file}.yaml" # 检查文件是否存在 if not template_path.exists(): raise YAMLError( f"模板文件不存在: {template_file}\n" f"查找位置: {templates_dir}\n" f"期望文件: {template_path}\n" f"提示: 请检查模板名称和模板目录是否正确" ) # 加载并验证模板文件 self.data = load_yaml_file(template_path) validate_template_yaml(self.data, str(template_path)) # 解析变量定义 self.vars_def = {} for var in self.data.get('vars', []): self.vars_def[var['name']] = var # 元素列表 self.elements = self.data.get('elements', []) def resolve_value(self, value, vars_values): """ 解析单个值中的变量引用 Args: value: 要解析的值 vars_values: 用户提供的变量值字典 Returns: 解析后的值 """ if not isinstance(value, str): return value # 匹配 {xxx} 模式 pattern = r'\{([^}]+)\}' def replacer(match): expr = match.group(1) # 模板变量: {title} if expr in vars_values: return str(vars_values[expr]) else: raise YAMLError(f"未定义的变量: {expr}") result = re.sub(pattern, replacer, value) # 如果结果是纯数字字符串,转换回数字类型 try: # 尝试转换为整数 if '.' not in result: return int(result) # 尝试转换为浮点数 else: return float(result) except ValueError: # 不是数字,返回字符串 return result def resolve_element(self, elem, vars_values): """ 递归解析元素中的所有变量 Args: elem: 元素(dict, list, 或其他类型) vars_values: 用户提供的变量值字典 Returns: 解析后的元素 """ if isinstance(elem, dict): return {k: self.resolve_element(v, vars_values) for k, v in elem.items() if k != 'visible'} elif isinstance(elem, list): return [self.resolve_element(item, vars_values) for item in elem] elif isinstance(elem, str): return self.resolve_value(elem, vars_values) else: return elem def evaluate_condition(self, condition, vars_values): """ 评估条件表达式(简单的存在性检查) Args: condition: 条件字符串,如 "{subtitle != ''}" vars_values: 变量值字典 Returns: bool: 条件是否满足 """ # 简单实现:检查变量是否非空 # 匹配 {var_name != ''} 或 {var_name != ""} pattern = r'\{(\w+)\s*!=\s*[\'\"]{2}\}' match = re.match(pattern, condition) if match: var_name = match.group(1) value = vars_values.get(var_name, '') return value != '' # 默认返回 True return True def render(self, vars_values): """ 渲染模板,返回实际的元素列表 Args: vars_values: 用户提供的变量值字典 Returns: list: 渲染后的元素列表 Raises: YAMLError: 缺少必需变量 """ # 填充所有变量的默认值(如果用户未提供) for var_name, var_def in self.vars_def.items(): if var_name not in vars_values: # 检查是否是必需变量 if var_def.get('required', False): # 必需变量必须有默认值或用户提供 if 'default' in var_def: vars_values[var_name] = self.resolve_value( var_def['default'], vars_values ) else: raise YAMLError(f"缺少必需变量: {var_name}") else: # 可选变量使用默认值(如果有) if 'default' in var_def: vars_values[var_name] = self.resolve_value( var_def['default'], vars_values ) # 渲染所有元素 rendered_elements = [] for elem in self.elements: # 检查条件渲染 if 'visible' in elem: if not self.evaluate_condition(elem['visible'], vars_values): continue # 深度解析元素中的所有变量引用 rendered_elem = self.resolve_element(elem, vars_values) rendered_elements.append(rendered_elem) return rendered_elements