forked from ScoDoc/DocScoDoc
migration exports xml
This commit is contained in:
parent
6f885edfe4
commit
dc726f1d10
21
README.md
21
README.md
@ -58,11 +58,28 @@ Installation:
|
||||
|
||||
donc utiliser:
|
||||
|
||||
pip install -r requirements.txt
|
||||
pip install -r requirements-2.7.txt
|
||||
|
||||
pour régénerer ce fichier:
|
||||
|
||||
pip freeze > requirements.txt
|
||||
pip freeze > requirements-2.7.txt
|
||||
|
||||
## Setup python3.7
|
||||
Debian 10 est livré avec Python 3.7.
|
||||
|
||||
apt-get install python3-dev
|
||||
apt-get install python3-venv
|
||||
python3 -m venv venv
|
||||
|
||||
Puis installation de Flask:
|
||||
|
||||
source venv/bin/activate
|
||||
pip install flask
|
||||
pip install wheel
|
||||
|
||||
Installer les dépendances:
|
||||
|
||||
pip install -r requirements-2.7.txt
|
||||
|
||||
## Bases de données
|
||||
ScoDoc8 utilise les bases de département de ScoDoc7, mais une nouvelle base
|
||||
|
@ -43,11 +43,10 @@ Par exemple, la clé '_css_row_class' spécifie le style CSS de la ligne.
|
||||
from __future__ import print_function
|
||||
import random
|
||||
from collections import OrderedDict
|
||||
|
||||
# XML generation package (apt-get install jaxml)
|
||||
import jaxml
|
||||
from xml.etree import ElementTree
|
||||
import json
|
||||
|
||||
from xml.etree import ElementTree
|
||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak
|
||||
from reportlab.platypus import Table, TableStyle, Image, KeepInFrame
|
||||
from reportlab.lib.colors import Color
|
||||
@ -59,6 +58,7 @@ from app.scodoc import html_sco_header
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc import sco_excel
|
||||
from app.scodoc import sco_pdf
|
||||
from app.scodoc import sco_xml
|
||||
from app.scodoc.sco_pdf import SU
|
||||
from app.scodoc.notes_log import log
|
||||
|
||||
@ -567,28 +567,25 @@ class GenTable(object):
|
||||
The tag names <table> and <row> can be changed using
|
||||
xml_outer_tag and xml_row_tag
|
||||
"""
|
||||
doc = jaxml.XML_document(encoding=scu.SCO_ENCODING)
|
||||
getattr(doc, self.xml_outer_tag)(
|
||||
id=self.table_id, origin=self.origin or "", caption=self.caption or ""
|
||||
doc = ElementTree.Element(
|
||||
self.xml_outer_tag,
|
||||
id=self.table_id,
|
||||
origin=self.origin or "",
|
||||
caption=self.caption or "",
|
||||
)
|
||||
doc._push()
|
||||
for row in self.rows:
|
||||
doc._push()
|
||||
x_row = ElementTree.Element(self.xml_row_tag)
|
||||
row_title = row.get("row_title", "")
|
||||
if row_title:
|
||||
getattr(doc, self.xml_row_tag)(title=row_title)
|
||||
else:
|
||||
getattr(doc, self.xml_row_tag)()
|
||||
x_row.set("title", row_title)
|
||||
doc.append(x_row)
|
||||
for cid in self.columns_ids:
|
||||
doc._push()
|
||||
v = row.get(cid, "")
|
||||
if v is None:
|
||||
v = ""
|
||||
getattr(doc, cid)(value=str(v))
|
||||
doc._pop()
|
||||
doc._pop()
|
||||
doc._pop()
|
||||
return repr(doc)
|
||||
x_cell = ElementTree.Element(cid, value=str(v))
|
||||
x_row.append(x_cell)
|
||||
return sco_xml.XML_HEADER + ElementTree.tostring(doc)
|
||||
|
||||
def json(self):
|
||||
"""JSON representation of the table."""
|
||||
|
@ -102,7 +102,7 @@ import app.scodoc.notesdb as ndb
|
||||
from app.scodoc.notes_log import log
|
||||
from app.scodoc.sco_exceptions import ScoValueError, FormatError
|
||||
from app.scodoc.gen_tables import GenTable
|
||||
from app.scodoc.sco_formsemestre import ApoEtapeVDI
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
from app.scodoc.sco_codes_parcours import code_semestre_validant
|
||||
from app.scodoc.sco_codes_parcours import (
|
||||
ADC,
|
||||
|
@ -38,7 +38,7 @@ from app.scodoc import sco_users
|
||||
from app.scodoc.gen_tables import GenTable
|
||||
from app.scodoc.notes_log import log
|
||||
from app.scodoc.sco_codes_parcours import NO_SEMESTRE_ID
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
||||
@ -385,100 +385,6 @@ def _write_formsemestre_aux(context, sem, fieldname, valuename):
|
||||
cnx.commit()
|
||||
|
||||
|
||||
# ------ Utilisé pour stocker le VDI avec le code étape (noms de fichiers maquettes et code semestres)
|
||||
class ApoEtapeVDI(object):
|
||||
_ETAPE_VDI_SEP = "!"
|
||||
|
||||
def __init__(self, etape_vdi=None, etape="", vdi=""):
|
||||
"""Build from string representation, e.g. 'V1RT!111'"""
|
||||
if etape_vdi:
|
||||
self.etape_vdi = etape_vdi
|
||||
self.etape, self.vdi = self.split_etape_vdi(etape_vdi)
|
||||
elif etape:
|
||||
if self._ETAPE_VDI_SEP in etape:
|
||||
raise ScoValueError("valeur code etape invalide")
|
||||
self.etape, self.vdi = etape, vdi
|
||||
self.etape_vdi = self.concat_etape_vdi(etape, vdi)
|
||||
else:
|
||||
self.etape_vdi, self.etape, self.vdi = "", "", ""
|
||||
|
||||
def __repr__(self):
|
||||
return self.__class__.__name__ + "('" + str(self) + "')"
|
||||
|
||||
def __str__(self):
|
||||
return self.etape_vdi
|
||||
|
||||
def _cmp(self, other):
|
||||
"""Test égalité de deux codes étapes.
|
||||
Si le VDI des deux est spécifié, on l'utilise. Sinon, seul le code étape est pris en compte.
|
||||
Donc V1RT == V1RT!111, V1RT!110 == V1RT, V1RT!77 != V1RT!78, ...
|
||||
|
||||
Compare the two objects x (=self) and y and return an integer according to
|
||||
the outcome. The return value is negative if x < y, zero if x == y
|
||||
and strictly positive if x > y.
|
||||
"""
|
||||
if other is None:
|
||||
return -1
|
||||
if type(other) == str:
|
||||
other = ApoEtapeVDI(other)
|
||||
|
||||
if self.vdi and other.vdi:
|
||||
x = (self.etape, self.vdi)
|
||||
y = (other.etape, other.vdi)
|
||||
else:
|
||||
x = self.etape
|
||||
y = other.etape
|
||||
|
||||
return (x > y) - (x < y)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._cmp(other) == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
return self._cmp(other) != 0
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._cmp(other) < 0
|
||||
|
||||
def __le__(self, other):
|
||||
return self._cmp(other) <= 0
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._cmp(other) > 0
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._cmp(other) >= 0
|
||||
|
||||
def split_etape_vdi(self, etape_vdi):
|
||||
"""Etape Apogee can be stored as 'V1RT' or, including the VDI version,
|
||||
as 'V1RT!111'
|
||||
Returns etape, VDI
|
||||
"""
|
||||
if etape_vdi:
|
||||
t = etape_vdi.split(self._ETAPE_VDI_SEP)
|
||||
if len(t) == 1:
|
||||
etape = etape_vdi
|
||||
vdi = ""
|
||||
elif len(t) == 2:
|
||||
etape, vdi = t
|
||||
else:
|
||||
raise ValueError("invalid code etape")
|
||||
return etape, vdi
|
||||
else:
|
||||
return etape_vdi, ""
|
||||
|
||||
def concat_etape_vdi(self, etape, vdi=""):
|
||||
if vdi:
|
||||
return self._ETAPE_VDI_SEP.join([etape, vdi])
|
||||
else:
|
||||
return etape
|
||||
|
||||
|
||||
"""
|
||||
[ ApoEtapeVDI('V1RT!111'), ApoEtapeVDI('V1RT!112'), ApoEtapeVDI('VCRT'), ApoEtapeVDI('V1RT') ]
|
||||
"""
|
||||
|
||||
|
||||
def sem_set_responsable_name(context, sem):
|
||||
"ajoute champs responsable_name"
|
||||
sem["responsable_name"] = ", ".join(
|
||||
|
@ -37,8 +37,8 @@ from app.scodoc import sco_groups
|
||||
from app.scodoc.notes_log import log
|
||||
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
|
||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||
from app.scodoc.sco_formsemestre import ApoEtapeVDI
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import sco_codes_parcours
|
||||
from app.scodoc import sco_compute_moy
|
||||
|
@ -50,7 +50,7 @@ from app.scodoc.gen_tables import GenTable
|
||||
from app.scodoc.notes_log import log
|
||||
from app.scodoc.sco_etape_bilan import EtapeBilan
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc.sco_formsemestre import ApoEtapeVDI
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
||||
|
@ -43,10 +43,10 @@ import time
|
||||
import types
|
||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
||||
import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
|
||||
import xml.sax.saxutils
|
||||
|
||||
|
||||
# XML generation package (apt-get install jaxml)
|
||||
import jaxml
|
||||
import jaxml # XXX
|
||||
|
||||
try:
|
||||
import six
|
||||
@ -66,8 +66,11 @@ from config import Config
|
||||
|
||||
from app.scodoc.SuppressAccents import suppression_diacritics
|
||||
from app.scodoc.notes_log import log
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
from app.scodoc.sco_xml import quote_xml_attr
|
||||
from app.scodoc.sco_codes_parcours import NOTES_TOLERANCE, CODES_EXPL
|
||||
from app.scodoc import sco_exceptions
|
||||
from app.scodoc import sco_xml
|
||||
from app.scodoc import VERSION
|
||||
|
||||
# ----- TEMPORAIRE POUR MIGRATION SCODOC7 -> SCODOC8 avant python3
|
||||
@ -445,74 +448,6 @@ def unescape_html_dict(d):
|
||||
unescape_html_dict(v)
|
||||
|
||||
|
||||
def quote_xml_attr(data):
|
||||
"""Escape &, <, >, quotes and double quotes"""
|
||||
return xml.sax.saxutils.escape(str(data), {"'": "'", '"': """})
|
||||
|
||||
|
||||
def dict_quote_xml_attr(d, fromhtml=False):
|
||||
"""Quote XML entities in dict values.
|
||||
Non recursive (but probbaly should be...).
|
||||
Returns a new dict.
|
||||
"""
|
||||
if fromhtml:
|
||||
# passe d'un code HTML a un code XML
|
||||
return dict([(k, quote_xml_attr(unescape_html(v))) for (k, v) in d.items()])
|
||||
else:
|
||||
# passe d'une chaine non quotée a du XML
|
||||
return dict([(k, quote_xml_attr(v)) for (k, v) in d.items()])
|
||||
|
||||
|
||||
def simple_dictlist2xml(dictlist, doc=None, tagname=None, quote=False):
|
||||
"""Represent a dict as XML data.
|
||||
All keys with string or numeric values are attributes (numbers converted to strings).
|
||||
All list values converted to list of childs (recursively).
|
||||
*** all other values are ignored ! ***
|
||||
Values (xml entities) are not quoted, except if requested by quote argument.
|
||||
|
||||
Exemple:
|
||||
simple_dictlist2xml([ { 'id' : 1, 'ues' : [{'note':10},{}] } ], tagname='infos')
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<infos id="1">
|
||||
<ues note="10" />
|
||||
<ues />
|
||||
</infos>
|
||||
|
||||
"""
|
||||
if not tagname:
|
||||
raise ValueError("invalid empty tagname !")
|
||||
if not doc:
|
||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
||||
scalar_types = [bytes, str, int, float]
|
||||
for d in dictlist:
|
||||
doc._push()
|
||||
if (
|
||||
type(d) == types.InstanceType or type(d) in scalar_types
|
||||
): # pour ApoEtapeVDI et listes de chaines
|
||||
getattr(doc, tagname)(code=str(d))
|
||||
else:
|
||||
if quote:
|
||||
d_scalar = dict(
|
||||
[
|
||||
(k, quote_xml_attr(v))
|
||||
for (k, v) in d.items()
|
||||
if type(v) in scalar_types
|
||||
]
|
||||
)
|
||||
else:
|
||||
d_scalar = dict(
|
||||
[(k, v) for (k, v) in d.items() if type(v) in scalar_types]
|
||||
)
|
||||
getattr(doc, tagname)(**d_scalar)
|
||||
d_list = dict([(k, v) for (k, v) in d.items() if type(v) == list])
|
||||
if d_list:
|
||||
for (k, v) in d_list.items():
|
||||
simple_dictlist2xml(v, doc=doc, tagname=k, quote=quote)
|
||||
doc._pop()
|
||||
return doc
|
||||
|
||||
|
||||
# Expressions used to check noms/prenoms
|
||||
FORBIDDEN_CHARS_EXP = re.compile(r"[*\|~\(\)\\]")
|
||||
ALPHANUM_EXP = re.compile(r"^[\w-]+$", re.UNICODE)
|
||||
@ -615,15 +550,13 @@ def sendPDFFile(REQUEST, data, filename):
|
||||
|
||||
class ScoDocJSONEncoder(json.JSONEncoder):
|
||||
def default(self, o): # pylint: disable=E0202
|
||||
from app.scodoc import sco_formsemestre
|
||||
|
||||
# ScoDoc 7.22 n'utilise plus mx:
|
||||
if str(type(o)) == "<type 'mx.DateTime.DateTime'>":
|
||||
log("Warning: mx.DateTime object detected !")
|
||||
return o.strftime("%Y-%m-%dT%H:%M:%S")
|
||||
if isinstance(o, (datetime.date, datetime.datetime)):
|
||||
return o.isoformat()
|
||||
elif isinstance(o, sco_formsemestre.ApoEtapeVDI):
|
||||
elif isinstance(o, ApoEtapeVDI):
|
||||
return str(o)
|
||||
else:
|
||||
return json.JSONEncoder.default(self, o)
|
||||
@ -641,14 +574,9 @@ def sendXML(REQUEST, data, tagname=None, force_outer_xml_tag=True):
|
||||
data = [data] # always list-of-dicts
|
||||
if force_outer_xml_tag:
|
||||
root_tagname = tagname + "_list"
|
||||
doc = jaxml.XML_document(encoding=SCO_ENCODING)
|
||||
getattr(doc, root_tagname)()
|
||||
doc._push()
|
||||
else:
|
||||
doc = None
|
||||
doc = simple_dictlist2xml(data, doc=doc, tagname=tagname)
|
||||
if force_outer_xml_tag:
|
||||
doc._pop()
|
||||
data = [{root_tagname: data}]
|
||||
doc = sco_xml.simple_dictlist2xml(data, tagname=tagname)
|
||||
|
||||
if REQUEST:
|
||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||
return repr(doc)
|
||||
|
121
app/scodoc/sco_vdi.py
Normal file
121
app/scodoc/sco_vdi.py
Normal file
@ -0,0 +1,121 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Emmanuel Viennet emmanuel.viennet@viennet.net
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
"""Classe stockant le VDI avec le code étape (noms de fichiers maquettes et code semestres)
|
||||
"""
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
class ApoEtapeVDI(object):
|
||||
_ETAPE_VDI_SEP = "!"
|
||||
|
||||
def __init__(self, etape_vdi=None, etape="", vdi=""):
|
||||
"""Build from string representation, e.g. 'V1RT!111'"""
|
||||
if etape_vdi:
|
||||
self.etape_vdi = etape_vdi
|
||||
self.etape, self.vdi = self.split_etape_vdi(etape_vdi)
|
||||
elif etape:
|
||||
if self._ETAPE_VDI_SEP in etape:
|
||||
raise ScoValueError("valeur code etape invalide")
|
||||
self.etape, self.vdi = etape, vdi
|
||||
self.etape_vdi = self.concat_etape_vdi(etape, vdi)
|
||||
else:
|
||||
self.etape_vdi, self.etape, self.vdi = "", "", ""
|
||||
|
||||
def __repr__(self):
|
||||
return self.__class__.__name__ + "('" + str(self) + "')"
|
||||
|
||||
def __str__(self):
|
||||
return self.etape_vdi
|
||||
|
||||
def _cmp(self, other):
|
||||
"""Test égalité de deux codes étapes.
|
||||
Si le VDI des deux est spécifié, on l'utilise. Sinon, seul le code étape est pris en compte.
|
||||
Donc V1RT == V1RT!111, V1RT!110 == V1RT, V1RT!77 != V1RT!78, ...
|
||||
|
||||
Compare the two objects x (=self) and y and return an integer according to
|
||||
the outcome. The return value is negative if x < y, zero if x == y
|
||||
and strictly positive if x > y.
|
||||
"""
|
||||
if other is None:
|
||||
return -1
|
||||
if type(other) == str:
|
||||
other = ApoEtapeVDI(other)
|
||||
|
||||
if self.vdi and other.vdi:
|
||||
x = (self.etape, self.vdi)
|
||||
y = (other.etape, other.vdi)
|
||||
else:
|
||||
x = self.etape
|
||||
y = other.etape
|
||||
|
||||
return (x > y) - (x < y)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._cmp(other) == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
return self._cmp(other) != 0
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._cmp(other) < 0
|
||||
|
||||
def __le__(self, other):
|
||||
return self._cmp(other) <= 0
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._cmp(other) > 0
|
||||
|
||||
def __ge__(self, other):
|
||||
return self._cmp(other) >= 0
|
||||
|
||||
def split_etape_vdi(self, etape_vdi):
|
||||
"""Etape Apogee can be stored as 'V1RT' or, including the VDI version,
|
||||
as 'V1RT!111'
|
||||
Returns etape, VDI
|
||||
"""
|
||||
if etape_vdi:
|
||||
t = etape_vdi.split(self._ETAPE_VDI_SEP)
|
||||
if len(t) == 1:
|
||||
etape = etape_vdi
|
||||
vdi = ""
|
||||
elif len(t) == 2:
|
||||
etape, vdi = t
|
||||
else:
|
||||
raise ValueError("invalid code etape")
|
||||
return etape, vdi
|
||||
else:
|
||||
return etape_vdi, ""
|
||||
|
||||
def concat_etape_vdi(self, etape, vdi=""):
|
||||
if vdi:
|
||||
return self._ETAPE_VDI_SEP.join([etape, vdi])
|
||||
else:
|
||||
return etape
|
||||
|
||||
|
||||
# [ ApoEtapeVDI('V1RT!111'), ApoEtapeVDI('V1RT!112'), ApoEtapeVDI('VCRT'), ApoEtapeVDI('V1RT') ]
|
95
app/scodoc/sco_xml.py
Normal file
95
app/scodoc/sco_xml.py
Normal file
@ -0,0 +1,95 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Emmanuel Viennet emmanuel.viennet@viennet.net
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
""" Exports XML
|
||||
"""
|
||||
|
||||
from xml.etree import ElementTree
|
||||
import xml.sax.saxutils
|
||||
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
|
||||
XML_HEADER = """<?xml version="1.0" encoding="utf-8"?>\n"""
|
||||
|
||||
|
||||
def quote_xml_attr(data):
|
||||
"""Escape &, <, >, quotes and double quotes"""
|
||||
return xml.sax.saxutils.escape(str(data), {"'": "'", '"': """})
|
||||
|
||||
|
||||
# ScoDoc7 legacy function:
|
||||
def simple_dictlist2xml(dictlist, doc=None, tagname=None, quote=False):
|
||||
"""Represent a dict as XML data.
|
||||
All keys with string or numeric values are attributes (numbers converted to strings).
|
||||
All list values converted to list of childs (recursively).
|
||||
*** all other values are ignored ! ***
|
||||
Values (xml entities) are not quoted, except if requested by quote argument.
|
||||
|
||||
Exemple:
|
||||
simple_dictlist2xml([ { 'id' : 1, 'ues' : [{'note':10},{}] } ], tagname='infos')
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<infos id="1">
|
||||
<ues note="10" />
|
||||
<ues />
|
||||
</infos>
|
||||
|
||||
"""
|
||||
if not tagname:
|
||||
raise ValueError("invalid empty tagname !")
|
||||
elements = _dictlist2xml(dictlist, root=[], tagname=tagname, quote=quote)
|
||||
return XML_HEADER + "\n".join([ElementTree.tostring(x) for x in elements])
|
||||
|
||||
|
||||
def _dictlist2xml(dictlist, root=None, tagname=None, quote=False):
|
||||
scalar_types = (bytes, str, int, float)
|
||||
for d in dictlist:
|
||||
elem = ElementTree.Element(tagname)
|
||||
root.append(elem)
|
||||
if isinstance(d, scalar_types) or isinstance(d, ApoEtapeVDI):
|
||||
elem.set("code", str(d))
|
||||
else:
|
||||
if quote:
|
||||
d_scalar = dict(
|
||||
[
|
||||
(k, quote_xml_attr(v))
|
||||
for (k, v) in d.items()
|
||||
if isinstance(v, scalar_types)
|
||||
]
|
||||
)
|
||||
else:
|
||||
d_scalar = dict(
|
||||
[(k, str(v)) for (k, v) in d.items() if isinstance(v, scalar_types)]
|
||||
)
|
||||
for k in d_scalar:
|
||||
elem.set(k, d_scalar[k])
|
||||
d_list = dict([(k, v) for (k, v) in d.items() if isinstance(v, list)])
|
||||
if d_list:
|
||||
for (k, v) in d_list.items():
|
||||
_dictlist2xml(v, tagname=k, root=elem, quote=quote)
|
||||
return root
|
Loading…
Reference in New Issue
Block a user