Skip to content

Commit 4369245

Browse files
committed
fix: single quoting
1 parent 280dc92 commit 4369245

File tree

2 files changed

+52
-48
lines changed

2 files changed

+52
-48
lines changed

xmodule/modulestore/xml_exporter.py

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""
22
Methods for exporting course data to XML
33
"""
4-
4+
from __future__ import annotations
55

66
import logging
77
import os
8+
import typing as t
89
from abc import abstractmethod
910
from json import dumps
1011

@@ -191,57 +192,59 @@ def _convert_attrs_to_single_quotes(xml_str: str) -> t.Iterable[str]:
191192
@@TODO document
192193
"""
193194
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 "&apos;" # 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 "&apos;" # 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 &quot; --> convert to literal double-qoute
218224
else:
219-
escape_code += c
220-
if escape_code == "quot":
221-
yield "\"" # Escape sequence is &quot; --> convert to literal double-qoute
225+
yield "&{escape_code};" # Any other escape sequence --> leave it as-is
222226
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
230234

231235

232236
def _write_xml(root_node: etree._Element, target_file: IO[str]) -> None:
233237
"""
234238
@@TODO does this work for libs and courses?
235239
@@TODO make it work for blocks
236240
"""
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+
245248

246249
class CourseExportManager(ExportManager):
247250
"""
@@ -261,7 +264,7 @@ def get_courselike(self):
261264
return self.modulestore.get_course(self.courselike_key, depth=None, lazy=False)
262265

263266
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:
265268
_write_xml(root, course_xml)
266269

267270
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
275278
# All asset types are exported using the "asset" tag - but their asset type is specified in each asset key.
276279
asset = lxml.etree.SubElement(asset_root, AssetMetadata.ASSET_XML_TAG)
277280
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:
279282
_write_xml(asset_root, asset_xml_file)
280283

281284
# export the static assets
@@ -403,7 +406,7 @@ def post_process(self, root, export_fs):
403406
called library.xml.
404407
"""
405408
# 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:
407410
_write_xml(root, xml_file)
408411

409412

xmodule/xml_block.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,9 @@ def add_xml_to_node(self, node):
472472
self.location.run if self.category == 'course' else url_path,
473473
)
474474
self.runtime.export_fs.makedirs(os.path.dirname(filepath), recreate=True)
475-
with self.runtime.export_fs.open(filepath, 'wb') as fileobj:
476-
ElementTree(xml_object).write(fileobj, pretty_print=True, encoding='utf-8')
475+
with self.runtime.export_fs.open(filepath, 'w') as fileobj:
476+
from xmodule.modulestore.xml_exporter import _write_xml
477+
_write_xml(xml_object, fileobj)
477478
else:
478479
# Write all attributes from xml_object onto node
479480
node.clear()

0 commit comments

Comments
 (0)