1
1
"""
2
2
Methods for exporting course data to XML
3
3
"""
4
-
4
+ from __future__ import annotations
5
5
6
6
import logging
7
7
import os
8
+ import typing as t
8
9
from abc import abstractmethod
9
10
from json import dumps
10
11
@@ -191,57 +192,59 @@ def _convert_attrs_to_single_quotes(xml_str: str) -> t.Iterable[str]:
191
192
@@TODO document
192
193
"""
193
194
xml_chars = iter (xml_str )
194
- while c := next (xml_chars ):
195
- # We're outside of any tag
196
- if c == "<" :
197
- yield "<"
198
- # We're inside a tag: < ... >
199
- while c := next (xml_chars ):
200
- if c == ">" :
201
- yield ">"
202
- break # Done with the tag, back to the outside
203
- elif c == "\" " :
204
- yield "'" # Yield single quote in place of double
205
- # We're inside an attribute value: <tagname yada=" ... ">
206
- while c := next (xml_chars ):
207
- if c == "\" " :
208
- yield "'" # Yield single quote in place of double
209
- break # Done with the attribute value, back to the tag
210
- elif c == "'" :
211
- yield "'" # Single quote in attr --> convert to escape sequence
212
- elif c == "&" :
213
- # We're inside an escape sequence: <tagname yada="blah &...; blah">
214
- escape_code = ""
215
- while c := next (xml_chars ):
216
- if c == ";" :
217
- break # Done with escape sequence
195
+ try :
196
+ while c := next (xml_chars ):
197
+ # We're outside of any tag
198
+ if c == "<" :
199
+ yield "<"
200
+ # We're inside a tag: < ... >
201
+ while c := next (xml_chars ):
202
+ if c == ">" :
203
+ yield ">"
204
+ break # Done with the tag, back to the outside
205
+ elif c == "\" " :
206
+ yield "'" # Yield single quote in place of double
207
+ # We're inside an attribute value: <tagname yada=" ... ">
208
+ while c := next (xml_chars ):
209
+ if c == "\" " :
210
+ yield "'" # Yield single quote in place of double
211
+ break # Done with the attribute value, back to the tag
212
+ elif c == "'" :
213
+ yield "'" # Single quote in attr --> convert to escape sequence
214
+ elif c == "&" :
215
+ # We're inside an escape sequence: <tagname yada="blah &...; blah">
216
+ escape_code = ""
217
+ while c := next (xml_chars ):
218
+ if c == ";" :
219
+ break # Done with escape sequence
220
+ else :
221
+ escape_code += c
222
+ if escape_code == "quot" :
223
+ yield "\" " # Escape sequence is " --> convert to literal double-qoute
218
224
else :
219
- escape_code += c
220
- if escape_code == "quot" :
221
- yield "\" " # Escape sequence is " --> convert to literal double-qoute
225
+ yield "&{escape_code};" # Any other escape sequence --> leave it as-is
222
226
else :
223
- yield "&{escape_code};" # Any other escape sequence --> leave it as-is
224
- else :
225
- yield c
226
- else :
227
- yield c
228
- else :
229
- yield c
227
+ yield c
228
+ else :
229
+ yield c
230
+ else :
231
+ yield c
232
+ except StopIteration :
233
+ pass
230
234
231
235
232
236
def _write_xml (root_node : etree ._Element , target_file : IO [str ]) -> None :
233
237
"""
234
238
@@TODO does this work for libs and courses?
235
239
@@TODO make it work for blocks
236
240
"""
237
- target_file .write (
238
- "" .join (
239
- _convert_attrs_to_single_quotes (
240
- lxml .etree .tostring (root_node , pretty_print = True , encoding = 'utf-8' )
241
- )
242
- )
243
- )
244
- #lxml.etree.ElementTree(root_node).(target_file, encoding='utf-8')
241
+ xml_str = lxml .etree .tostring (root_node , pretty_print = True , encoding = 'utf-8' ).decode ('utf-8' )
242
+ convert_quotes = lambda : True
243
+ if convert_quotes ():
244
+ target_file .write ("" .join (_convert_attrs_to_single_quotes (xml_str )))
245
+ else :
246
+ target_file .write (xml_str )
247
+
245
248
246
249
class CourseExportManager (ExportManager ):
247
250
"""
@@ -261,7 +264,7 @@ def get_courselike(self):
261
264
return self .modulestore .get_course (self .courselike_key , depth = None , lazy = False )
262
265
263
266
def process_root (self , root , export_fs ):
264
- with export_fs .open ('course.xml' , 'wb ' ) as course_xml :
267
+ with export_fs .open ('course.xml' , 'w ' ) as course_xml :
265
268
_write_xml (root , course_xml )
266
269
267
270
def process_extra (self , root , courselike , root_courselike_dir , xml_centric_courselike_key , export_fs ):
@@ -275,7 +278,7 @@ def process_extra(self, root, courselike, root_courselike_dir, xml_centric_cours
275
278
# All asset types are exported using the "asset" tag - but their asset type is specified in each asset key.
276
279
asset = lxml .etree .SubElement (asset_root , AssetMetadata .ASSET_XML_TAG )
277
280
asset_md .to_xml (asset )
278
- with OSFS (asset_dir ).open (AssetMetadata .EXPORTED_ASSET_FILENAME , 'wb ' ) as asset_xml_file :
281
+ with OSFS (asset_dir ).open (AssetMetadata .EXPORTED_ASSET_FILENAME , 'w ' ) as asset_xml_file :
279
282
_write_xml (asset_root , asset_xml_file )
280
283
281
284
# export the static assets
@@ -403,7 +406,7 @@ def post_process(self, root, export_fs):
403
406
called library.xml.
404
407
"""
405
408
# Create the Library.xml file, which acts as the index of all library contents.
406
- with export_fs .open (LIBRARY_ROOT , 'wb ' ) as xml_file :
409
+ with export_fs .open (LIBRARY_ROOT , 'w ' ) as xml_file :
407
410
_write_xml (root , xml_file )
408
411
409
412
0 commit comments