55from typing import Any , Optional
66
77from pydantic import BaseModel
8+ from pyspark .errors .exceptions .base import AnalysisException
89from pyspark .sql import DataFrame , SparkSession
910from pyspark .sql import functions as sf
1011from pyspark .sql .column import Column
1112from pyspark .sql .types import StringType , StructField , StructType
12- from pyspark .sql .utils import AnalysisException
1313from typing_extensions import Literal
1414
15- from dve .core_engine .backends .base .reader import BaseFileReader , read_function
16- from dve .core_engine .backends .exceptions import EmptyFileError
15+ from dve .core_engine .backends .base .reader import read_function
16+ from dve .core_engine .backends .exceptions import EmptyFileError , MessageBearingError
1717from dve .core_engine .backends .implementations .spark .spark_helpers import (
1818 df_is_empty ,
1919 get_type_from_annotation ,
2020 spark_write_parquet ,
2121)
22- from dve .core_engine .backends .readers .xml import XMLStreamReader
22+ from dve .core_engine .backends .readers .xml import BasicXMLFileReader , XMLStreamReader
2323from dve .core_engine .type_hints import URI , EntityName
2424from dve .parser .file_handling import get_content_length
2525from dve .parser .file_handling .service import open_stream
@@ -43,7 +43,7 @@ def read_to_dataframe(
4343 ) -> DataFrame :
4444 """Stream an XML file into a Spark data frame"""
4545 if not self .spark :
46- self .spark = SparkSession .builder .getOrCreate ()
46+ self .spark = SparkSession .builder .getOrCreate () # type: ignore
4747 spark_schema = get_type_from_annotation (schema )
4848 return self .spark .createDataFrame ( # type: ignore
4949 list (self .read_to_py_iterator (resource , entity_name , schema )),
@@ -52,7 +52,7 @@ def read_to_dataframe(
5252
5353
5454@spark_write_parquet
55- class SparkXMLReader (BaseFileReader ): # pylint: disable=too-many-instance-attributes
55+ class SparkXMLReader (BasicXMLFileReader ): # pylint: disable=too-many-instance-attributes
5656 """A reader for XML files built atop Spark-XML."""
5757
5858 def __init__ (
@@ -70,21 +70,33 @@ def __init__(
7070 sanitise_multiline : bool = True ,
7171 namespace = None ,
7272 trim_cells = True ,
73+ xsd_location : Optional [URI ] = None ,
74+ xsd_error_code : Optional [str ] = None ,
75+ xsd_error_message : Optional [str ] = None ,
76+ rules_location : Optional [URI ] = None ,
7377 ** _ ,
7478 ) -> None :
75- self .record_tag = record_tag
76- self .spark_session = spark_session or SparkSession .builder .getOrCreate ()
79+
80+ super ().__init__ (
81+ record_tag = record_tag ,
82+ root_tag = root_tag ,
83+ trim_cells = trim_cells ,
84+ null_values = null_values ,
85+ sanitise_multiline = sanitise_multiline ,
86+ xsd_location = xsd_location ,
87+ xsd_error_code = xsd_error_code ,
88+ xsd_error_message = xsd_error_message ,
89+ rules_location = rules_location ,
90+ )
91+
92+ self .spark_session = spark_session or SparkSession .builder .getOrCreate () # type: ignore
7793 self .sampling_ratio = sampling_ratio
7894 self .exclude_attribute = exclude_attribute
7995 self .mode = mode
8096 self .infer_schema = infer_schema
8197 self .ignore_namespace = ignore_namespace
82- self .root_tag = root_tag
8398 self .sanitise_multiline = sanitise_multiline
84- self .null_values = null_values
8599 self .namespace = namespace
86- self .trim_cells = trim_cells
87- super ().__init__ ()
88100
89101 def read_to_py_iterator (
90102 self , resource : URI , entity_name : EntityName , schema : type [BaseModel ]
@@ -106,6 +118,14 @@ def read_to_dataframe(
106118 if get_content_length (resource ) == 0 :
107119 raise EmptyFileError (f"File at { resource } is empty." )
108120
121+ if self .xsd_location :
122+ msg = self ._run_xmllint (file_uri = resource )
123+ if msg :
124+ raise MessageBearingError (
125+ "Submitted file failed XSD validation." ,
126+ messages = [msg ],
127+ )
128+
109129 spark_schema : StructType = get_type_from_annotation (schema )
110130 kwargs = {
111131 "rowTag" : self .record_tag ,
@@ -143,7 +163,7 @@ def read_to_dataframe(
143163 kwargs ["rowTag" ] = f"{ namespace } :{ self .record_tag } "
144164 df = (
145165 self .spark_session .read .format ("xml" )
146- .options (** kwargs )
166+ .options (** kwargs ) # type: ignore
147167 .load (resource , schema = read_schema )
148168 )
149169 if self .root_tag and df .columns :
0 commit comments