Il blog di Gianni Giaccaglini

Blog su VBA e VSTO
Gianni Giaccaglini

My Links

News

NB - V. anche gli ARTICOLI (in fondo a questa barra)
Solo quesiti validi a: giannigiac@tin.it
Il mio nuovo libro


La mia nipotina ELISA

Foto con dedica a ME di
Bill Gates giovanissimo
nei mitici anni 80!

Categorie Post

Categorie Articoli

Archivio

Immagini

Blog Stats

Recupero dati da un foglio Excel 2007 col VBA - Seconda soluzione

Recupero dati da un foglio Excel 2007 col VBA, seconda soluzione

Questo articolo fa seguito al mio primo intervento in materia:

http://blog.shareoffice.it/giannigiaccaglini/articles/9165.aspx

(è importante leggerlo, prima di proseguire…)

Prima di procedere, offro agli amanti delle varianti, una prima alternativa alla precedente soluzione.

Questa può essere resa più efficiente sostituendo il filtro della soluzione originale, che ottiene tutti i valori, senza distinguere quelli che sono indici di shared string, ossia, ripeto:

Set NodiXmlRif = DocXml.selectNodes("//sheetData/row/c/@r")

Set NodiXmlVal = DocXml.selectNodes("//sheetData/row/c/v")

con il filtro seguente, che seleziona I soli valori “reali” (numerici), riducendo così i tempi del caricamento di dati nelle celle del foglio ricostruito:

Set NodiXmlRif = DocXml.selectNodes("//sheetData/row/c[@s]/@r")

Set NodiXmlVal = DocXml.selectNodes("//sheetData/row/c[@s]/v")

Nota. La soluzione seguente di primo acchito può apparire valida:

Set NodiXmlRif = DocXml.selectNodes("//sheetData/row/c [@t!='s']/@r")

Set NodiXmlVal = DocXml.selectNodes("//sheetData/row/c[@t!='s']/v")

ma di fatto restituisce zero nodi, in quanto le celle contenenti valori “veri” non contengono nessun attributo t, bensì solo l’attributo s (esempio s=”3”).

(l’XPath è potente ma assai sottile,... idem l’OOXML!)

 

La nuova soluzione

Nel primo articolo avevo sinceramente confessato di non aver ben compreso come si applicasse la proprietà Attributes di un nodo XML (oggetto IXMLDOMNode), facendo appello a chi lo sapesse. La richiesta è caduta nel vuoto (suscitando commiserazione da parte degli esperti in materia? Non credo, oggi come oggi sono ben pochi...), Comunque nel frattempo ho compreso che il mio fraintendimento era, semplicemente, infondato (dico solo che dovevo far uso della proprietà parentNode, v. più avanti)

Sia come sia, ho così sviluppato un’alternativa basata sulla dannata proprietà Attributes In due parole, il nuovo algoritmo evita del tutto il filtraggio preventivo dei nodi c, li esplora tutti, utilizzando ciascuno di essi in conformità ai suoi attributi. Altra variante interessante  consiste nell’uso diretto di sharedStrings.xml, in luogo del vettore della precedente soluzione.

Nota bene. sharedStrings.xml viene caricato in uno specifico DOMDocument, ossia DocXmlCond, distinto rispetto a DocXml, In tal modo essi si possono usare separatamente.

La nuova macro:

Sub RicostrDatiByAttrib(Cartxml As String)

  Dim DocXml As DOMDocument, DocXmlCond As DOMDocument

  Dim NodiXmlCond As IXMLDOMNodeList 'shared strings

  Dim NodiXml As IXMLDOMNodeList 'Tutti i nodi

  Dim NodoXml As IXMLDOMNode

  Set DocXmlCond = New DOMDocument 'DOMDocument per le sharedStrings

  DocXmlCond.async = False

  DocXmlCond.Load ("" & Cartxml & "\xl\sharedStrings.xml")

  Set NodiXmlCond = DocXmlCond.selectNodes("//t")

  'Esplora tutte le celle

  Set DocXml = New DOMDocument 'NB – Occorre un diverso DOMDocument

  DocXml.async = False

  DocXml.Load ("" & Cartxml & "\xl\worksheets\sheet1.xml")

  Set NodiXml = DocXml.selectNodes("//c/v")

  Dim NodoGenitore As IXMLDOMNode

  Dim Rifer As String, ValNodo As String, MaxAttr As Integer

  For Each NodoXml In NodiXml

    Set NodoGenitore = NodoXml.parentNode

    ValNodo = NodoXml.Text

    Rifer = NodoGenitore.Attributes(0).Text

    MaxAttr = NodoGenitore.Attributes.Length - 1

    If NodoGenitore.Attributes(MaxAttr).Text = "s" Then

      With Range(Rifer)

        .Value = NodiXmlCond(ValNodo).Text

        With .Interior

           .ThemeColor = xlThemeColorAccent5

           .TintAndShade = 0.6

        End With

      End With

    Else

      Range(Rifer) = ValNodo

    End If

  Next

End Sub

 

'Un semplice test:

Sub ProvaRicostrDati ()

  With WorkSheets(1)

    .Activate

    .UsedRange.Clear

  End With

  RicostrDatiByAttrib "C:\CartMioFoglio"

End Sub

Anche qui l’ipotesi è che nella cartella di file C:\CartMioFoglio siano stati estratti gli archivi xml del nostro MioFoglio.xlsx (v. articolo precedente).

Altre osservazioni

·         NodiXmlRif e NodiXmlVal fanno riferimento ai nodi v (valori) e @r (riferimenti di cella) come nella soluzione precedente, ma senza filtraggio.

·         Gli attributi  che ci interessano sono quelli dei nodi c¸ i quali si possono ottenere con l’istruzione ripetuta qui sotto per comodità:
Set NodoGenitore = NodoXml.parentNode

·         Gli attributi del nodo ‘c possono essere 2 o 3, comunque quello che ci interessa è l’ultimo, pertanto l’istruzione seguente fornisce il suo indice nell’insieme Attributes (N.B. l’indice del primo elemento s è 0):
MaxAttr = NodoGenitore.Attributes.Length – 1

?>

posted on lunedì 19 novembre 2007 12.07