Feat: Sidebar mit Suchfilter und lxml-Parser im XslDependencyDialog
- Ein-/ausblendbare Sidebar mit tab-übergreifender Suche hinzugefügt - Graph-Suchfilter blendet nicht-betroffene XSL-Dateien aus dem Netzwerkgraph aus - Regex-basierte XSL-Abhängigkeitserkennung durch lxml-Parser ersetzt - Suchfilter wird beim Tab-Wechsel erneut angewendet Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+26
-9
@@ -7,13 +7,28 @@ Der Graph wird im Speicher gehalten und bei Änderungen (mtime) automatisch inva
|
||||
"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
from lxml import etree
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Regex für xsl:import und xsl:include href-Attribute
|
||||
_IMPORT_INCLUDE_PATTERN = re.compile(r'<xsl:(?:import|include)\s+href=["\']([^"\']+)["\']', re.IGNORECASE)
|
||||
_XSL_NAMESPACE = "http://www.w3.org/1999/XSL/Transform"
|
||||
|
||||
|
||||
def _parse_import_include_hrefs(content: str) -> list[str]:
|
||||
"""Parst XSL-Dateiinhalt und gibt alle href-Werte von xsl:import/xsl:include zurück."""
|
||||
try:
|
||||
root = etree.fromstring(content.encode("utf-8"))
|
||||
except etree.XMLSyntaxError:
|
||||
return []
|
||||
hrefs = []
|
||||
for tag in ("import", "include"):
|
||||
for elem in root.iter(f"{{{_XSL_NAMESPACE}}}{tag}"):
|
||||
href = elem.get("href")
|
||||
if href:
|
||||
hrefs.append(href)
|
||||
return hrefs
|
||||
|
||||
|
||||
class XslDependencyGraph:
|
||||
@@ -84,8 +99,7 @@ class XslDependencyGraph:
|
||||
return result
|
||||
|
||||
# Finde alle import/include-Referenzen
|
||||
for match in _IMPORT_INCLUDE_PATTERN.finditer(content):
|
||||
href = match.group(1)
|
||||
for href in _parse_import_include_hrefs(content):
|
||||
referenced_path = (xsl_file.parent / href).resolve()
|
||||
|
||||
if referenced_path.exists() and referenced_path not in visited:
|
||||
@@ -138,12 +152,14 @@ class XslDependencyGraph:
|
||||
if not xsl_root_dir.exists():
|
||||
return graph
|
||||
|
||||
start = time.perf_counter()
|
||||
for xsl_file in sorted(xsl_root_dir.rglob("*.xsl")):
|
||||
xsl_file = xsl_file.resolve()
|
||||
deps = self.get_dependencies(xsl_file)
|
||||
graph[xsl_file] = deps
|
||||
elapsed = time.perf_counter() - start
|
||||
|
||||
logger.info(f"Vollständiger XSL-Graph aufgebaut: {len(graph)} Dateien")
|
||||
logger.info(f"Vollständiger XSL-Graph aufgebaut: {len(graph)} Dateien in {elapsed:.3f}s")
|
||||
return graph
|
||||
|
||||
def _get_direct_dependencies(self, xsl_file: Path) -> set[Path]:
|
||||
@@ -168,8 +184,7 @@ class XslDependencyGraph:
|
||||
logger.warning(f"Konnte XSL-Datei nicht lesen: {xsl_file} ({e})")
|
||||
return result
|
||||
|
||||
for match in _IMPORT_INCLUDE_PATTERN.finditer(content):
|
||||
href = match.group(1)
|
||||
for href in _parse_import_include_hrefs(content):
|
||||
referenced_path = (xsl_file.parent / href).resolve()
|
||||
if referenced_path.exists():
|
||||
result.add(referenced_path)
|
||||
@@ -191,11 +206,13 @@ class XslDependencyGraph:
|
||||
if not xsl_root_dir.exists():
|
||||
return graph
|
||||
|
||||
start = time.perf_counter()
|
||||
for xsl_file in sorted(xsl_root_dir.rglob("*.xsl")):
|
||||
xsl_file = xsl_file.resolve()
|
||||
graph[xsl_file] = self._get_direct_dependencies(xsl_file)
|
||||
elapsed = time.perf_counter() - start
|
||||
|
||||
logger.info(f"Direkter XSL-Graph aufgebaut: {len(graph)} Dateien")
|
||||
logger.info(f"Direkter XSL-Graph aufgebaut: {len(graph)} Dateien in {elapsed:.3f}s")
|
||||
return graph
|
||||
|
||||
def invalidate(self, xsl_file: Path | None = None):
|
||||
|
||||
Reference in New Issue
Block a user