LeenO computo metrico con LibreOffice  3.22.0
Il software libero per la gestione di computi metrici e contabilità lavori.
LeenoImport_XmlSix.py
Vai alla documentazione di questo file.
1 """
2  LeenO - modulo parser XML per il formato XML-SIX
3 """
4 import Dialogs
5 import LeenoImport
6 import LeenoDialogs as DLG
7 
8 def parseXML(data, defaultTitle):
9  '''
10  estrae dal file XML i dati dell'elenco prezzi
11  I dati estratti avranno il formato seguente:
12 
13  articolo = {
14  'codice': codice,
15  'desc': desc,
16  'um': um,
17  'prezzo': prezzo,
18  'mdo': mdo,
19  'sicurezza': oneriSic
20  }
21  artList = { codice : articolo, ... }
22 
23  superCatList = { codice : descrizione, ... }
24  catList = { codice : descrizione, ... }
25 
26  dati = {
27  'titolo': titolo,
28  'superCategorie': superCatList,
29  'categorie': catList,
30  'articoli' : artList
31  }
32  '''
33 
34  # elimina i namespaces dai dati ed ottiene
35  # elemento radice dell' albero XML
37 
38  prezzario = root.find('prezzario')
39  descrizioni = prezzario.findall('przDescrizione')
40  lingue = {}
41  lingua = None
42  lingueEstese = {'it': 'Italiano', 'de': 'Deutsch', 'en': 'English', 'fr': 'Français', 'es': 'Español'}
43  try:
44  for desc in descrizioni:
45  lingua = desc.attrib['lingua']
46  lExt = lingueEstese.get(lingua, lingua)
47  lingue[lExt] = lingua
48  except KeyError:
49  pass
50 
51  if len(lingue) > 1:
52  lingue['Tutte'] = 'tutte'
53  lingue['Annulla'] = 'annulla'
54  lingua = Dialogs.MultiButton(
55  Icon="Icons-Big/question.png",
56  Title="Scelta lingue",
57  Text="Il file fornito è un prezzario multilinguale\n\nSelezionare la lingua da importare\noppure 'Tutte' per ottenere un prezzario multilinguale",
58  Buttons=lingue)
59  # se si chiude la finestra il dialogo ritorna 'None'
60  # lo consideriamo come un 'Annulla'
61  if lingua is None:
62  lingua = 'annulla'
63  if lingua == 'tutte':
64  lingua = None
65  else:
66  lingua = None
67 
68  if lingua == 'annulla':
69  return None
70 
71  # da qui, se lingua == None importa tutte le lingue presenti
72  # altrimenti solo quella specificata
73 
74  # estrae il nome
75  # se richiesta un lingua specifica, estrae quella
76  # altrimenti le estrea tutte e le concatena una dopo l'altra
77  nome = ""
78  if lingua is None:
79  nome = descrizioni[0].attrib['breve']
80  for desc in range(1, len(descrizioni)):
81  nome = nome + '\n' + descrizioni[desc].attrib['breve']
82  else:
83  for desc in descrizioni:
84  if desc.attrib['lingua'] == lingua:
85  nome = desc.attrib['breve']
86  break
87 
88  # legge le unità di misura
89  # siccome ci interessano soli i simboli e non il resto
90  # non serve il processing per le lingue
91  units = {}
92  umList = prezzario.findall('unitaDiMisura')
93  for um in umList:
94  attr = um.attrib
95  try:
96  if 'simbolo' in attr:
97  sym = attr['simbolo']
98  else:
99  sym = attr['udmId']
100  umId = attr['unitaDiMisuraId']
101  units[umId] = sym
102  except KeyError:
103  pass
104 
105  # se ci sono le categorie SOA, estrae prima quelle
106  # in versione a una o più lingue a seconda del file
107  # e di come viene richiesta la cosa
108  # attualmente non servono, ma non si sa mai...
109  categorieSOA = {}
110  catList = root.findall('categoriaSOA')
111  for cat in catList:
112  attr = cat.attrib
113  try:
114  soaId = attr['soaId']
115  soaCategoria = attr['soaCategoria']
116  descs = cat.findall('soaDescrizione')
117  text = ""
118  for desc in descs:
119  descAttr = desc.attrib
120  try:
121  descLingua = descAttr['lingua']
122  except KeyError:
123  descLingua = None
124  if lingua is None or descLingua is None or lingua == descLingua:
125  text = text + descAttr['breve'] + '\n'
126  if text != "":
127  text = text[: -len('\n')]
128 
129  categorieSOA[soaCategoria] = {'soaId': soaId, 'descrizione': text}
130  except KeyError:
131  pass
132 
133  # infine tiriamo fuori il prezzario
134  # utilizziamo le voci 'true' come base per le descrizioni
135  # aggiungendo quelle delle voci specializzate '.a, .b...'
136  baseCodice = ''
137  baseTextBreve = ''
138  baseTextEstesa = ''
139  artList = {}
140 
141  productList = prezzario.findall('prodotto')
142  madre = ''
143  for product in productList:
144  attr = product.attrib
145 
146  # il codice del prodotto
147  if not 'prdId' in attr:
148  continue
149  codice = attr['prdId']
150 
151  # se c'è, estrae l'unità di misura
152  if 'unitaDiMisuraId' in attr:
153  um = attr['unitaDiMisuraId']
154  # converte l'unità dal codice al simbolo
155  um = units.get(um, "*SCONOSCIUTA*")
156  else:
157  # unità non trovata - la lascia in bianco
158  um = ""
159 
160  # il prezzo
161  # alcune voci non hanno il campo del prezzo essendo
162  # voci principali composte da sottovoci
163  # le importo comunque, lasciando il valore nullo
164  try:
165  prezzo = float(product.find('prdQuotazione').attrib['valore'])
166  except Exception:
167  prezzo = ""
168  if prezzo == 0:
169  prezzo = ""
170 
171  # percentuale manodopera
172  mdo = ""
173  try:
174  mdo = float(product.find('incidenzaManodopera').text) / 100
175  except Exception:
176  mdo = ""
177  if mdo == 0:
178  mdo = ""
179 
180  # oneri sicurezza
181  try:
182  oneriSic = float(attr['onereSicurezza'])
183  except Exception:
184  oneriSic = ""
185  if oneriSic == 0:
186  oneriSic = ""
187 
188  # per le descrizioni, come sempre... processing a seconda
189  # della lingua disponibile / richiesta
190  descs = product.findall('prdDescrizione')
191  textBreve = ""
192  textEstesa = ""
193  madre = ""
194  for desc in descs:
195  descAttr = desc.attrib
196  try:
197  descLingua = descAttr['lingua']
198  except KeyError:
199  descLingua = None
200  if lingua is None or descLingua is None or lingua == descLingua:
201 
202  if 'breve' in descAttr and 'estesa' in descAttr:
203  if descAttr['breve'] in descAttr['estesa']:
204  textBreve = descAttr['estesa'] + '\n'
205  else:
206  textEstesa = descAttr['estesa'] + '\n- ' + descAttr['breve'] + '\n'
207  madre = textEstesa[: -len('\n')]
208 
209  if descAttr['breve'] == descAttr['estesa']:
210  textEstesa = madre + descAttr['breve'] + '\n'
211 
212  if 'breve' in descAttr and not 'estesa' in descAttr:
213  if descAttr['breve'][2] in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
214  textEstesa = madre + descAttr['breve'] + '\n'
215  else:
216  textEstesa = madre + descAttr['breve'] + '\n'
217 
218  textBreve = textBreve.replace('Ó', 'à').replace('Þ', 'é').replace('','').replace('
','').replace('
','').replace(''',"'")
219  textEstesa = textEstesa.replace('Ó', 'à').replace('Þ', 'é').replace('','').replace('
','').replace('
','').replace(''',"'")
220 
221  if textBreve != "":
222  textBreve = textBreve[: -len('\n')]
223  if textEstesa != "":
224  textEstesa = textEstesa[: -len('\n')]
225 
226  # controlla se la voce è una voce 'base' o una specializzazione
227  # della voce base. Il campo 'voce' è totalmente inaffidabile, quindi
228  # consideriamo come 'base' delle voci a valore nullo e le azzeriamo
229  # ad ogni nuova base e/o cambio di numerazione
230  base = (prezzo == "")
231  if not base and not codice.startswith(baseCodice):
232  baseTextBreve = ""
233  baseTextEstesa = ""
234 
235  # se voce base, tiene buona la descrizione e la salva anche come base
236  # per le prossime voci (estese). Per funzionare, questo presuppone che
237  # nell' XML le voci estese seguano quella base in ordine, e che tutte le voci
238  # siano correttamente etichettate come voce = 'true' se voci base
239  # probabilmente si può fare di meglio...
240  if base:
241  baseTextBreve = textBreve + '\n'
242  baseTextEstesa = textEstesa + '\n'
243  baseCodice = codice
244 
245  if not base and codice.startswith(baseCodice):
246  textBreve = baseTextBreve +'- '+ textBreve
247  textEstesa = baseTextEstesa +'- '+ textEstesa
248 
249  # utilizza solo la descrizione lunga per LeenO
250  if len(textBreve) > len(textEstesa):
251  desc = textBreve
252  else:
253  desc = textEstesa
254 
255  if len(codice.split('.')) == 4:
256  madre = desc
257  if len(codice.split('.')) > 4:
258  if madre not in desc:
259  desc = madre + desc
260 
261  # giochino per garantire che la prima stringa abbia una lunghezza minima
262  # in modo che LO formatti correttamente la cella
263  # ~desc = LeenoImport.fixParagraphSize(desc)
264 
265  # gruppo, nel caso ci sia
266  try:
267  grpId = product.find('prdGrpValore').attrib['grpValoreId']
268  except Exception:
269  grpId = ""
270 
271  # compone l'articolo e lo mette in lista
272  # esclude dall'elenco le voci senza prezzo
273  if len(codice.split('.')) > 2 and prezzo != '':
274  artList[codice] = {
275  'codice': codice,
276  'desc': desc,
277  'um': um,
278  'prezzo': prezzo,
279  'mdo': mdo,
280  'sicurezza': oneriSic,
281  'gruppo': grpId
282  }
283 
284  # in alcuni casi sono presenti i gruppi, che poi sono le nostre
285  # supercategorie e categorie
286  # i gruppi hanno, ovviamente, una numerazione e degli ID che non c'entrano
287  # un tubo con gli articoli... ma gli articoli portano un riferimento al gruppo
288  # quindi una volta letti gli articoli bisogna fare uno scan a rovescio per
289  # ritrovare i codici corretti delle categorie
290  gruppi = {}
291  superGruppi = {}
292  try:
293  gruppo = root.find('gruppo')
294  grpValori = gruppo.findall('grpValore')
295  for grpValore in grpValori:
296  continue # non capisco perché, ma senza questa riga va in errore
297  grpId = grpValore.attrib['grpValoreId']
298  vlrId = grpValore.attrib['vlrId']
299  vlrDesc = grpValore.find('vlrDescrizione').attrib['breve']
300  if '.' in vlrId:
301  sgId = vlrId.split('.')[0]
302  gruppi[grpId] = {'cat': vlrId, 'desc': vlrDesc, 'superGroup': sgId}
303  else:
304  superGruppi[vlrId] = vlrDesc
305  except Exception:
306  pass
307 
308  # crea le categorie e supercategoria
309  # è un po' un caos, ma è l'unico modo rapido per farlo
310  catList = {}
311  superCatList = {}
312  if len(gruppi) > 0:
313  for codice, articolo in artList.items():
314  try:
315  splitCodice = codice.split('.')
316  codiceCat = splitCodice[0] + '.' + splitCodice[1]
317  codiceSuperCat = splitCodice[0]
318  except:
319  pass
320  gruppo = articolo['gruppo']
321  if gruppo is None or gruppo == '':
322  continue
323  groupData = gruppi[gruppo]
324  if not codiceCat in catList:
325  catList[codiceCat] = groupData['desc']
326  if not codiceSuperCat in superCatList:
327  superCatList[codiceSuperCat] = superGruppi[groupData['superGroup']]
328 
329  return {
330  'titolo': defaultTitle,
331  'superCategorie': superCatList,
332  'categorie': catList,
333  'articoli' : artList
334  }
LeenoImport_XmlSix.parseXML
def parseXML(data, defaultTitle)
Definition: LeenoImport_XmlSix.py:8
Dialogs.MultiButton
def MultiButton(*Icon=None, Title='', Text='', Buttons=None)
Definition: Dialogs.py:2649
LeenoImport.stripXMLNamespaces
def stripXMLNamespaces(data)
Definition: LeenoImport.py:47