per vuott, ambassador gambas... ;D
Ho riscontrato un'altro problema, legato alla libreria gb.xml, in particolare con XMLWriter (ma probabilemnte c'è qualcosa anche con XMLReader).
Faccio un esempio che forse rende meglio l'idea. Io devo scrivere un file xml, con una serie di tag nidificati, dove la maggior parte degli elementi hanno un un'uico valore (Text), come ad esempio:
<Tags>
<Tag1>valore</Tag1>
<Tag2>valore</Tag2>
</Tags>
Come si può notare, Tag1 e Tag2 hanno un valore, e questo viene racchiuso tra l'apertura del tag "<Tag1>", e la sua chiusura "/Tag1>".
Fino a qui la logica credo sia semplice e chiara, e questa è stata finora adottata in tutte le mie applicazioni, compreso pgDesigner (che di file xml ne legge parecchi).
Dovo aver scaricato l'ultima versione di Gambas3 in formato sorgente, oggi è la 4827, ho riscontrato che la lettura ha qualcosa che non và (ancora da chiarire), mentre la scrittura ha un errore, che ho verificato nei sorgenti della classe XmlWriter.class, di cui posto la parte interessata al problema:
Public Sub StartElement(TagName As String, Optional Attributes As String[], Optional Prefix As String, Optional URI As String)
Dim Xmlns, s, sData As String
Dim i As Integer = 0
If URI Then
Xmlns = " xmlns"
If Prefix Then Xmlns &= ":" & Prefix
Xmlns &= "=\"" & URI & "\""
Endif
If Prefix Then TagName = Prefix & ":" & TagName
sData = "<" & TagName
If Attributes
If (Attributes.Count Mod 2) Then Attributes.Push("")
For i = 0 To Attributes.Max Step 2
sData &= " " & Attributes[i] & "=\"" & Attributes[i + 1] & "\""
Next
Endif
sData &= Xmlns
If Not $TagEnded Then 'On ferme le tag précédent
Write(">" & If($indent, "\n", ""), True)
Endif
$TagEnded = False
Write(sData)
PileElements.Push(TagName)
End
Public Sub EndElement()
Dim tag As String
If Not PileElements.Count Then Return
tag = PileElements.Pop()
If Not $TagEnded Then 'On ferme le tag précédent
Write(" />" & If($indent, "\n", ""), True) 'Pas de contenu
$TagEnded = True
Else
Write("</" & tag & ">")
Endif
End
il codice applica una logica errata, o perlomeno parte da un presupposto non completamente corretto. In pratica il tag viene aperto e chiuso tramite lo stato della variabile $TagEnded, non tenendo conto che potrebbe esserci un valore Text in mezzo. Questo causa la scrittura errata del tag, come da esempio:
<Tag1valore />
<Tag2valore />
in pratica unisce il nome del tag con il valore stesso.
La sequenza con cui viene aperto e chiuso il tag, e associato a questo un valore è come da esempio:
DIM oXml As XmlWriter
...
oXml.StartElement("Tag1")
oXml.Text("valore")
oXml.EndElement()
Con la versione 3.1.1 la cosa funzionava, ma ora con gli ultimi aggiornamenti non và più. Non sò se dalla 3.1.1, le build successive riportano tutte lo stesso problema, ma di sicuro la 4827.
Caro vuott, dato che scrivere direttamente a Benoit mi è sempre restato piuttosto difficoltoso, sarebbe di gran utilità (e non solo per me), notificare a Minisini questo problema, per poter correggere al più presto.
Tieni conto che il pezzo di sorgente ad inizio post è estratto dalla classe inclusa nei sorgenti di gambas, ed è scritta nello stesso linguaggio, per cui è semplice sistemarla.
Grazie
Ho scaricato l'ultima versione dei sorgenti di Gambas3 (4833), ma le anomalie persistono.
Il seguente è il codice che stò utilizzando, e che è un estratto depurato di quello originale usato in pgDesigner3, per la lettura del file di configurazione, che prima funzionava e ora non và più:
Public Sub Main()
Dim reader As New XmlReader
Dim s As String[]
reader.Open("/home/luigi/tmp/text.xml")
While (Not reader.Eof)
s = [reader.Node.Depth,
reader.Node.Name,
reader.Node.Type,
reader.Node.Value,
reader.Node.Attributes.Count]
Print "[" & s.Join("],[") & "]"
Print reader.Node.Dep
Select Case reader.Node.Type
Case XmlReaderNodeType.Element
Print "Element::" & reader.Node.Name, reader.Node.Value
For Each reader.Node.Attributes
Print reader.Node.Name, reader.Node.Value
Next
Case XmlReaderNodeType.EndElement
Print "EndElement::"
Case XmlReaderNodeType.Text
Print "Text::" & reader.Node.Value
End Select
Print "Read = " & reader.Read() 'return EndStream
Wend
End
ci sono alcuni Print, per capire cosa contengono le variabili, ma sono tutte vuote. I problemi non cambiano, sia con Open() che con fromString().
Ho anche usato il file di prova contenuto nei sorgenti di gambas "text.xml", il cui contenuto è molto semplice:
<?xml version="1.0"?>
<toto machin="toto">Hello<truc>Bouh</truc><!-- Hello -->
</toto>
<titi>Hellow</titi>
In allegato invio anche quello usato per la versione di pgDesigner3 che stò sviluppando, e che è un tantino più grande e più articolato.
Stò cercando di localizzare il problema nei sorgenti di gambas3 ma non riesco a trovare il bandolo della matassa, in quanto parte è in linguaggio gambas, parte è in C, parte è di libreria esterna...
I haven't finished my analysis, but I noticed one error in your code :
(PgXmlDocument.class, line 79)
Select Case oXml.Node.Type
'[...]
Case XmlReaderNodeType.EndElement
EndElement is not a node type, but a state, so Node.Type will never return this. You should use the State property instead :
Select Case oXml.State
'[...]
Case XmlReaderNodeType.EndElement'Ok
And, another question, are all your files encoded in UTF-8 ?
Thanks, exams are done now, just waiting for the results ... :)
And I finally found the problem.
The good code (that doesn't crashes libxml) should be that :
Public Sub Main()
Dim reader As New XmlReader
reader.Open("text.xml")
reader.Read()
While Not reader.Eof
Print reader.Node.Type
If reader.Node.Type = XmlNode.CommentNode Then Print reader.Node.Value
reader.Read()
Wend
End
I've got this with gb.xml :
... and this with gb.libxml :
Numbers (and so readed elements) are missing, now I've just to find why.
Too late. I found what the problem was. :)
I solved it in the last revision (#4855 I think), and also updated the test module and the XML test file, so that they are compatible with libxml and more explicit :
' Gambas module file
Public Sub Main()
Dim reader As New XmlReader
reader.Open("text.xml")
reader.Read()
While Not reader.Eof
Print reader.Node.Type;;
Select Case reader.Node.Type
Case XmlReaderNodeType.Element
Print "element"
Case XmlReaderNodeType.Attribute
Print "attribute"
Case XmlReaderNodeType.Text
Print "text"
Case XmlReaderNodeType.Comment
Print "comment"
Case XmlReaderNodeType.EndElement
Print "endelement"
Default
Print ""
End Select
reader.Read()
Wend
End
<?xml version="1.0"?>
<toto machin="toto">Hello<truc>Bouh</truc><!-- Hello --></toto>
Here are the new results on my machine, first with gb.libxml :
1 element
3 text
1 element
3 text
15 endelement
8 comment
15 endelement
.. and then with gb.xml :
1 element
2 text
1 element
2 text
6 endelement
3 comment
6 endelement
Results are the same, so I think the bug is solved, please tell me if you have the same behaviour with the last revision.
The spaces problem is in your code.
For Example, I replaced this line :
Print "Element::" & reader.Node.Name, reader.Node.Value
... by this one :
Print "Element::" & reader.Node.Name & reader.Node.Value
And there isn't spaces anymore.
No.
Taking the example of loading file pgdesigner.conf (attached), using the code:
Static Public Sub Main()
Dim reader As New XmlReader
Dim writer As New XmlWriter
Dim arr As String[]
reader.Open("/home/luigi/tmp/pgdesigner3.conf")
While (Not reader.Eof)
arr = ["Type=" & reader.Node.Type,
"Name=" & reader.Node.Name,
"Value=" & reader.Node.Value,
"Depth=" & reader.Node.Depth,
"Attributes=" & reader.Node.Attributes.Count]
Print "Row[" & arr.Join("],[") & "]"
Select Case reader.Node.Type
Case XmlReaderNodeType.Element
Print "Element[name=[" & reader.Node.Name & "], value=[" & reader.Node.Value & "]]"
For Each reader.Node.Attributes
Print "Attribute[name=[" & reader.Node.Name & "], value=[" & reader.Node.Value & "]]"
Next
Case XmlReaderNodeType.EndElement
Print "EndElement[]"
Case XmlReaderNodeType.Text
Print "Text[value=[value=[" & reader.Node.Value & "]]"
End Select
reader.Read()
Wend
reader.Close()
the second and the third line shows:
with gb.xml
Row[Type=1],[Name=pgDesigner3 ],[Value=],[Depth=1],[Attributes=3]
Element[name=[pgDesigner3 ], value=[]]
with gb.libxml
Row[Type=1],[Name=pgDesigner3],[Value=],[Depth=1],[Attributes=3]
Element[name=[pgDesigner3], value=[]]
that, as you can see, gb.xml adds a space at the end of string "pgDesigner3".
I downloaded the 4912 version.
Now the speed is equal with the two libraries.
I noticed, however, in the header of the xml file is no longer stored the encoding:
<?xml version="1.0" encoding="UTF-8"?> #with gb.libxml
<?xml version="1.0"?> #with gb.xml
thanks.
Maybe another problem, maybe i misunderstood the doc:
XmlElement.GetAttribute (gb.xml)
Function GetAttribute ( Name As String ) As String
Returns the attribute Name.
Should return the Value of Attribute "Name"?
With the following code:
Public Sub Main()
Dim oRoot As XmlElement
Dim oDoc As XmlDocument
Dim iVar As Integer
Dim oReader As XmlReader
oDoc = New XmlDocument
oDoc.Open("language")
oRoot = oDoc.Root
Debug oRoot.Name
Debug oRoot.Children.Count
For iVar = 0 To oRoot.ChildElements.Max
Print oRoot.ChildElements[iVar].GetAttribute("name")
Print oRoot.ChildElements[iVar].GetAttribute("code")
Print oRoot.ChildElements[iVar].GetAttribute("region")
Next
End
i got
name
code
region
while i expect:
Milan
MI
Lombardia
see the attached file.
Hi Prokopy,
I have a bad new for you.
If you try to read an non existing Attribute a signal 11 occurs. (Rev. #4925)
Use the following code with the file cities attached in my previous post:
Public Sub Main()
Dim oRoot As XmlElement
Dim oDoc As XmlDocument
Dim iVar As Integer
Dim oReader As XmlReader
oDoc = New XmlDocument
oDoc.Open("cities.txt")
oRoot = oDoc.Root
Debug oRoot.Name
Debug oRoot.Children.Count
For iVar = 0 To oRoot.ChildElements.Max
Print oRoot.ChildElements[iVar].GetAttribute("name")
Print oRoot.ChildElements[iVar].GetAttribute("cod") ' should be "code"
Print oRoot.ChildElements[iVar].GetAttribute("region")
Next
End
Attached the debugger output.
Hum, I think there is a mistake in your code. This line does not crashes :
Print oRoot.ChildElements[iVar].GetAttribute("cod")
... but this one does :
Print oRoot.ChildElements[iVar].Attributes["cod"]
We can see in the debugger output that the CElementAttributes_get method is called, not the CElement_getAttributes one.
Anyway, this is solved in the revision #4927. Thanks. :)