Source code for xsdata.tool
from dataclasses import dataclass
from dataclasses import field
from pathlib import Path
from typing import List
from typing import Optional
from typing import Union
from xsdata.builder import ClassBuilder
from xsdata.logger import logger
from xsdata.models.elements import Import
from xsdata.models.elements import Include
from xsdata.models.elements import Override
from xsdata.models.elements import Redefine
from xsdata.models.enums import Namespace
from xsdata.parser import SchemaParser
from xsdata.reducer import reducer
from xsdata.writer import writer
SchemaLocator = Union[Import, Include, Redefine, Override]
[docs]@dataclass
class ProcessTask:
print: bool
renderer: str
processed: List[Path] = field(init=False, default_factory=list)
[docs] def process(
self,
xsd: Path,
package: str,
target_namespace: Optional[str] = None,
redefine: Optional[Redefine] = None,
):
if xsd in self.processed:
logger.debug("Circular import skipping: %s", xsd.name)
return
self.processed.append(xsd)
parser = SchemaParser(target_namespace=target_namespace)
schema = parser.from_xsd_path(xsd)
for sub_schema in schema.sub_schemas():
self.process_import(sub_schema, xsd, package, schema.target_namespace)
logger.info("Schema: %s, elements: %d", xsd.name, schema.num)
classes = ClassBuilder(schema=schema, redefine=redefine).build()
logger.info("Class candidates: %d", len(classes))
classes = reducer.process(schema=schema, classes=classes)
logger.info("Class graduated: %d", len(classes))
callback = writer.print if self.print else writer.write
callback(
schema=schema, classes=classes, package=package, renderer=self.renderer
)
[docs] def process_import(
self,
schema: SchemaLocator,
path: Path,
package: str,
target_namespace: Optional[str],
):
sub_xsd_package = None
sub_xsd_path = self.resolve_local_schema(schema)
if schema.schema_location is None:
return
elif sub_xsd_path is None:
sub_xsd_path = self.resolve_schema(path, schema)
sub_xsd_package = self.adjust_package(package, schema)
redefine = schema if isinstance(schema, Redefine) else None
self.process(
xsd=sub_xsd_path,
package=sub_xsd_package or package,
target_namespace=target_namespace,
redefine=redefine,
)
[docs] @staticmethod
def resolve_local_schema(schema: SchemaLocator) -> Optional[Path]:
if not isinstance(schema, (Override, Redefine)) and schema.namespace:
ns = Namespace.get_enum(schema.namespace)
uri = schema.schema_location
if ns and (not uri or uri.startswith("http")):
path = (
Path(__file__)
.absolute()
.parent.joinpath(f"schemas/{ns.prefix}.xsd")
)
schema.schema_location = str(path)
return path
return None
[docs] @staticmethod
def resolve_schema(xsd: Path, schema: SchemaLocator) -> Path:
assert schema.schema_location is not None
return xsd.parent.joinpath(schema.schema_location).resolve()
[docs] @staticmethod
def adjust_package(package: str, schema: SchemaLocator) -> str:
assert schema.schema_location is not None
pp = package.split(".")
for part in Path(schema.schema_location).parent.parts:
if part == "..":
pp.pop()
else:
pp.append(part)
return ".".join(pp)