[GELÖST] Buchstabenweises kopieren eines Strings?

Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Neue Antwort erstellen

 

CO2

ehemals "SirMO"

Betreff: [GELÖST] Buchstabenweises kopieren eines Strings?

BeitragSa, Dez 31, 2011 0:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,
ich versuche gerade einen XML-Parser zu bauen und stehe gerade ziemlich auf dem Schlauch Crying or Very sad .
Ich lasse eine Zeile aus einer XML-Datei auslesen und möchte diese unterteilen, allerdings soll das nicht statisch sein, also das man später nicht immer genau 1 Leerzeichen zwischen den attributen machen muss, oder das die attribute nicht immer genau in der selben reihenfolge sein müssen. Meine probier-XML-Datei sieht wie folgt aus: Code: [AUSKLAPPEN]
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<vehicle>
   <id>$VEH_AMBULANCE$</id>
   <name>Krankenwagen</name>
   <model file="mod\ambulance.2dm"/>
   <motion accelerate="" deccelerate="" maxspeed=""/>
   <multiplayer active="true">
      <seat>6</seat>
   </multiplayer>
   <fuel type="2" usage="" capacity="85"/>
   <engine>
      <cylinder>6</cylinder>
      <ps>125</ps>
   </engine>
   <coord>
      <turnpoint x="" y=""/>
      <exhaustpoint x="" y=""/>
   </coord>
</vehicle>
(leere Strings nicht beachten, werden noch gefüllt Wink )

Und die Funktion die das auslesen soll sieht momentan so aus: BlitzMax: [AUSKLAPPEN]
Function ReadVehicleXML(File:String)
Local XMLFile:TStream = ReadFile(File)
Local Line:String
Local NewVehicle:Vehicle = New Vehicle
Repeat
Line = Trim(ReadLine(XMLFile))
If(Left(Line, 2) = "<?")
Continue
EndIf
If(Left(Line, 9) = "<vehicle>")
If(Left(Line, 4) = "<id>")

EndIf
EndIf
Until Eof(XMLFile)
CloseFile(XMLFile)
End Function
("Vehicle" ist ein von mir definierter Type Wink )
Kurz zur erklärung: Eine Zeile wird ausgelesen und getrimmt. Wenn die ersten zwei zeichen des Strings "<?" sind, nächste Zeile auslesen. Wenn allerdings die ersten 9 Zeichen des Strings "<vehicle>" entsprechen, dann... und ab hier weiß ich nicht weiter. Wie lese ich z.B.: die "motion"-Zeile (in der XML-Datei) aus? Oder wie kann ich einen String solange kopieren, bis der end-Tag kommt (z.B.: bei dem "id"-Tag)?

Ich hoffe ihr könnt mir helfen
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti
  • Zuletzt bearbeitet von CO2 am Mi, Jan 11, 2012 21:09, insgesamt einmal bearbeitet

d-bug

BeitragSa, Dez 31, 2011 1:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Gaaaaaanz wichtig: Beschäftige dich umgehend mit Slices und dem Typ String im allgemeinen.
Lese dazu bitte die Hilfe von BlitzMax.

z.B. Um aus der Zeile den Tag "<Vehicle>" zuverlässig raus zubekommen nutze doch einfach String.replace(" ","") wenn du sicher bist dass es sich nur um Leerzeichen handelt, ansonsten: string[string.find("<")..string.find(">")] ...da fehlt aber noch irgendwo die Korrektur der Position...

usw. usw. usw.

Mit dem BRL.Retro Modul kommst du bei BlitzMax nicht immer ans Ziel! Außerdem ist es absolut veraltet! Wink

Midimaster

BeitragSa, Dez 31, 2011 10:50
Antworten mit Zitat
Benutzer-Profile anzeigen
ist natürlich ein nettet Tipp! Berührt aber in keinster Weise seine Frage.

Leider habe ich noch nie eine Parser gecoded, aber ich würde es so anfangen:

Sobald der TAG <Vehicle> aufgetaucht ist, kommen ja wahrscheinlich anschließend seine Parameter. Ich würde beim Erscheinen eines bestimmten TAGs einen TYPE für die zu erwartenden Parameter anlegen und anschließend in eine Funktion springennen, um dort die folgenden Zeilen auswerten. Da ja die Reihenfolge nicht zugesichert ist, füllst Du eben immr das Element, das Du gerade zufällig findest. Entscheidendes Zeichen für einen TAG-Beginn ist immer das "<", du trennst den daran hängenden String heraus (bis zum ">") und verzweigst dann in eine entsprechende tiefere Funktion, möglicherweise wieder mit einem neuen TYPE. Dort wird der Inhalt ausgelesen und in den TYPE übertragen.
Am Ende überprüft man, ob dieser TAG ordnungsgmäß endet. und gibt den entstandenen TYPE an die höherliegende Funktion zurück. So müßte sich allmählich der Verhicle-TYPE und seine sub-TYPEN füllen.

Pseudocode:
Code: [AUSKLAPPEN]

NextTag$ = FindeTag(RestText$)
Select NextTag$
     Case "vehicle"
          Vehicle:VehicleTyp=ZerlegeVehicle()
End Select

Function ZerlegeVehicle:VehicleTyp()
    local loc:VehicleTyp
    local locText$ = SchneideTag("/Id", RestText)
    NextTag$ = FindeTag(locText$)
    Select NextTag$
         Case "Id"
              loc.Id=SchneideTag("/Id", locText)
         Case "name"
              loc.name=SchneideTag("/name", locText)
         Case "/verhicle"
              Return loc
     End Select
End Function 


wo mehrere Parameter zu erwarten sind zweigst du wieder in eine Sub-Funktion. Hier am Beispiel von "motion":
Code: [AUSKLAPPEN]
.....
Function ZerlegeVehicle:VehicleTyp()
    local loc:VehicleTyp
    local locText$ = SchneideTag("/Id", RestText)
    NextTag$ = FindeTag(locText$)
    Select NextTag$
         Case "Id"
              loc.Id=SchneideTag("/Id", locText)
         Case "motion"
              loc.motion=ZerlegeMotion(locText)
         ......
End Function
......
Function ZerlegeMotion:MotionTyp(RestText$)
    local loc:MotionTyp
    local locText$ = SchneideTag("/motion", RestText)
    NextTag$ = FindeTag(locText$)
    Parameter$ = FindeParameter(RestText$)
    Select Parameter$
         Case "accelerate"
                loc.Accelerate=WertZu("accelerate=",RestText)
          Case "maxspeed"
                loc.MaxSpeed=WertZu("maxspeed=",RestText)
          Case "/>
                Return loc
End Function


Vorsicht: Das ist hier nur Pseudo-Code. Nur ein Entwurf. Bedenke auch ich hab sowas noch nie gemacht, und kann dir keine Garantie geben, dass dies der richtige Weg ist. Der Teufel steckt bei Parsern im Detail! Vor allem ist es wichtig zu erkennen, wann man den gelesenen TAG endgültig aus dem RestText$ entfernt.

Die Funktion FindeParameter() soll immer den nächsten Parameter innerhalb von TAG-Grenzen finden, die Funktion SchneideTag() findet immer was zwischen einen Start-Tag und einen End-Tag steht.
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe

ZEVS

BeitragSa, Dez 31, 2011 11:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Meine Methode für Parser ist ziemlich unübersichtlich, aber schnell und sicher. Du gehst einfach das gesamte Dokument einmal durch, Zeichen für Zeichen und schaust halt, was das bedeuten soll. Lässt sich eigentlich auf alles anwenden, nur halt ist die Schleife ziemlich lang.
Ein Ausschnitt aus meinem XML-Modul:
BlitzMax: [AUSKLAPPEN]

Function LoadFromString:TDomDocument(content$)
Local document:TDomDocument = New TDomDocument
Local root:TDomNode = New TDomNode
document.root = root
Local parentNode:TDomNode = root, currentNode:TDomNode, currentAttr$, inEntity%, entityContent$
Local currentValue$, currentQuote$, isCollapsed%, textContent$, tagName$, commentEnd$
'tausend Arbeitsvariablen
Const STATE_OUTSIDETAG% = 1
Const STATE_TAGNAME% = 2
Const STATE_INTAG% = 3
Const STATE_INATTR% = 4
Const STATE_INVALUE% = 5
Const STATE_INQUOTES% = 6
Const STATE_CLOSETAG% = 7
Const STATE_INCOMMENT% = 8
Local currentState% = STATE_OUTSIDETAG 'was für ein Status hat die aktuell geparste Stelle?
content = Trim(content)
If content.StartsWith("<?xml") Then 'XML-Header entfernen
Local pos% = content.Find("?>")
Assert pos <> -1, "XML-Header not closed"
content = content[pos+2..]
EndIf
Local pos% = 0
For pos = 0 Until Len(content)
Local c$ = content[pos..pos+1] 'Zeichen an der Position pos auswählen
Local add% = True 'Zeichen zum Text hinzufügen?
Select currentState 'Je nach Status andere Aktion
Case STATE_OUTSIDETAG 'außerhalb eines Tags
If inEntity Then 'in einem Entity
add = False 'nicht zum Text hinzufügen
If c = ";" Then 'Entity-Ende
Local value$ = String(MapValueForKey(Self.entities, entityContent)) 'Entity aus Map lesen
Assert value, "Unknown entity: "+entityContent
textContent :+ value 'Entity-Content hinzufügen
entityContent = ""
inEntity = False
Else
entityContent :+ c 'Zeichen zum Entity hinzufügen
EndIf
Else 'Außerhalb eines Tags und Entities
Select c
Case "&" 'Entity
inEntity = True
add = False
Case "<" 'Tag
textContent = Trim(textContent)
If textContent Then
Local node:TTextNode = TTextNode.Create(textContent, parentNode)
textContent = ""
EndIf
currentState = STATE_TAGNAME 'Wir sind bei einem Tag-Namen angekommen
add = False 'geöffnete Klammer nicht hinzufügen
End Select
If add Then textContent :+ c
EndIf
Case STATE_TAGNAME 'im Tagnamen
If inEntity Then 'gleiches Spiel mit Entities
add = False
If c = ";" Then
Local value$ = String(MapValueForKey(Self.entities, entityContent))
Assert value, "Unknown entity: "+entityContent
tagName :+ value
entityContent = ""
inEntity = False
Else
entityContent :+ c
EndIf
Else
Select c
Case "&"
inEntity = True
add = False
Case " ", "~t", "~r", "~n", ">" 'Tagname-Ende (Whitespace oder Klammer zu)
If tagName.startsWith("/") Then 'Schließendes Tag
tagName = tagName[1..]
Assert tagName = parentNode.name,..
"Cannot close "+tagName+" (parent is "+parentNode.name+")"
currentState = STATE_CLOSETAG 'in schließendem Tag
If c = ">" Then 'Tag gleich geschlossen
currentState = STATE_OUTSIDETAG
isCollapsed = False
add = False
parentNode = parentNode.parent
EndIf
Else
If tagName.endsWith("/") Then 'Tagname endet mit / => Standalone-tag wie <br/>
tagName = tagName[..Len(tagName)-1]
isCollapsed = True
EndIf
currentNode = TDomNode.Create(tagName, parentNode)
currentState = STATE_INTAG 'In einem Tag
If c = ">" Then 'Tag geschlossen
currentState = STATE_OUTSIDETAG
isCollapsed = False
add = False
parentNode = currentNode
EndIf
EndIf
tagName = ""
add = False 'Whitespace/geschlossene Klammer nicht hinzufügen
End Select
EndIf
If add Then tagName :+ c
If tagName = "!--" Then 'Kommentar
tagName = ""
currentState = STATE_INCOMMENT
EndIf
Case STATE_INTAG 'In einem Tag
Select c
Case " ", "~t", "~r", "~n" 'Whitespace
'do nothing
Case "/" 'Standalone-Tag wie <br />
isCollapsed = True
Case ">" 'Tag geschlossen
currentState = STATE_OUTSIDETAG
If Not isCollapsed Then parentNode = currentNode
isCollapsed = False
add = False
Default 'Kein Whitespace, nichts anderes => Attribut
currentState = STATE_INATTR
currentAttr = c 'Attribut beginnt mit c
End Select
Case STATE_INATTR 'In einem Attribut
If inEntity Then 'Entity...
add = False
If c = ";" Then
Local value$ = String(MapValueForKey(Self.entities, entityContent))
Assert value, "Unknown entity: "+entityContent
currentAttr :+ value
entityContent = ""
inEntity = False
Else
entityContent :+ c
EndIf
Else
Select c
Case "&" 'Entity
inEntity = True
add = False
Case "=" 'Gleichheitszeichen
currentState = STATE_INQUOTES 'Als nächstes kommen die Anführungszeichen
add = False
End Select
EndIf
If add Then currentAttr :+ c
Case STATE_INQUOTES 'Anführungszeichen
Select c
Case "~q", "'" 'doppelt oder einfach
currentQuote = c 'speichern um zweites zu erkennen
currentState = STATE_INVALUE 'Im Wert
Default 'Kein Anführungszeichen nach Gleichheitszeichen?
RuntimeError "Cannot set an attribute's value without quotes"
End Select
Case STATE_INVALUE 'In einem Attribut-Wert
If inEntity Then 'Entity
add = False
If c = ";" Then
Local value$ = String(MapValueForKey(Self.entities, entityContent))
Assert value, "Unknown entity: "+entityContent
currentValue :+ value
entityContent = ""
inEntity = False
Else
entityContent :+ c
EndIf
Else
Select c
Case "&" 'Entity
inEntity = True
add = False
Case currentQuote 'Das Anführungszeichen, mit dem der Wert eingeleitet wurde => Wert-Ende
currentNode.setAttribute currentAttr, currentValue
currentState = STATE_INTAG 'Wieder im Tag
add = False
currentAttr = ""
currentValue = ""
End Select
EndIf
If add Then currentValue :+ c
Case STATE_CLOSETAG 'Schließendes Tag wie </p>
Select c
Case " ", "~t", "~r", "~n" 'Whitespace
'ok
Case ">" 'geschlossen
currentState = STATE_OUTSIDETAG 'Außerhalb eines Tags
parentNode = parentNode.parent
Assert parentNode, "Closed root" 'Geschlossen, wo nicht geöffnet wurde
Default 'sonst darf nichts hier rein
RuntimeError "Invalid character "+c+" in close-tag"
End Select
Case STATE_INCOMMENT 'Im Kommentar
commentEnd :+ c 'commentEnd enthält die letzten drei Buchstaben des Kommentars
If Len(commentEnd) > 3 Then commentEnd = commentEnd[1..] 'abschneiden
If commentEnd = "-->" Then 'Kommentar-Ende
commentEnd = ""
currentState = STATE_OUTSIDETAG 'Wieder im Text
EndIf
End Select
Next
Return document
End Function


Es lässt ein bisschen mehr durchgehen, als es eigentlich dürfte und beherrscht nicht das ganze XML mit CDATA und DTDs, aber mir reicht es.

Falls Interesse am Rest-Code besteht, kann ich reinstellen.

ZEVS

d-bug

BeitragSa, Dez 31, 2011 12:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Minimaster hat Folgendes geschrieben:
ist natürlich ein nettet Tipp! Berührt aber in keinster Weise seine Frage.


Doch, eigentlich schon. Nur sehe ich nicht ein ihm den fertigen Code zu geben. Auf diese weise reicht ihm nämlich mehr oder weniger copy-paste und der Lernfaktor bleibt auf der Strecke.

Grüße

ZEVS

BeitragSa, Dez 31, 2011 12:18
Antworten mit Zitat
Benutzer-Profile anzeigen
Es ist kein fertiger Code. Es fehlt nämlich noch das Modul darum. Ohne intensive Auseinandersetzung bekommst du den nicht zum Laufen Razz .
Außerdem gibt es wahrscheinlich irgendwo hier oder im englischen Portal einen XML-Reader, den du Copy+Pasten kannst. Ich glaube, FDM hatte sowas bei denem letzten BCC-Beitrag, da kann man auch klauen. Wenn es CO2 darum ginge, dann würde er diesen Thread nicht so eröffnen.

Ich bleibe dabei: Wenn Interesse am Rest-Code besteht, stelle ich den rein.

ZEVS

BladeRunner

Moderator

BeitragSa, Dez 31, 2011 15:31
Antworten mit Zitat
Benutzer-Profile anzeigen
ZEVS: Buggies Antwort galt ja nicht Dir, sondern Midimaster. Und ich stimme ihm voll zu: Seine Antwort hat mit der Fragestellung sogar sehr viel zu tun, denn Slices sind ein famoser Weg um Parsing zu betreiben.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

CO2

ehemals "SirMO"

BeitragSa, Dez 31, 2011 18:38
Antworten mit Zitat
Benutzer-Profile anzeigen
So, dann werd ich mal anfangen:

@ d-bug: Ok, hab mir mal eben über google ausspucken lassen, was slices sind. Damit könnte das funktionieren, werde es auf jeden fall mal ausprobieren Wink

@ Midimaster: Ok, mal sehen ob ich das verstanden habe: Ich brauche also einen Vehicle-Type, sowie einen (?) zwei (?) Sub-Type(n). Diese beinhalten dann z.b. die werte der parameter in den Tags, der eine speichert die parameter die zwischen 2 Tags stehen (also z.b.: "<digit>45</digit>"), der andere die, die in einem Tag stehen (z.B.: "<digit amount="45"/>")? Oder wie?

@ ZEVS: Zitat:
Dokument einmal durch, Zeichen für Zeichen
- Das ist das Problem, was ich habe Wink
Mir reichte es, wenn es nur die Parameter aus den Tags auslesen könnte... Very Happy Ohne Kommentare, CData und was es da nicht alles gibt...
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Xeres

Moderator

BeitragSa, Dez 31, 2011 18:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Mein Tipp: Nimm einfach ein fertiges Modul z.B. Libxml von Brucey und setz deine Zeit für das Spiel ein.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
 

CO2

ehemals "SirMO"

BeitragDi, Jan 03, 2012 21:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,
Es hat mir doch keine Ruhe gelassen, also hab ich 2 Funktionen geschrieben. Die eine Ließt Parameter zwischen 2 Tags aus ("<Digit>23</Digit>"), die andere ließt Parameter in einem Tag aus ("<Digit amount="42"/>") - Allerdings macht letztere Probleme: Wenn ich mehr als 1 Parameter in einem Tag auslesen will, kriege ich einen Fehler: "Unhandled Exception: Attempt to index array element beyond array length".
Hier mal die Funktion BlitzMax: [AUSKLAPPEN]
Function GetParamInTag(Line:String, NumberOfParams:Int, ReadParams:String[])
Local TrimLine:String = Trim(Line)
Local ParamWithOutZoll:String[] = TrimLine.split(Chr(34))
Local x = 0
Local y = 1
While(x < NumberOfParams)
ReadParams[x] = ParamWithOutZoll[y]
x = x + 1
y = y + 2
Wend
End Function


Hier die Zeile die ausgelesen werden soll Code: [AUSKLAPPEN]
<motion accelerate="0.0025" deccelerate="0.005" maxspeed="80"/>


Und hier mal der Funktionsaufruf BlitzMax: [AUSKLAPPEN]
		If(Left(Line, 7) = "<motion") 'Bewegung
Local TempMotionSaver:String[]
GetParamInTag(Line, 3, TempMotionSaver)
TempVehicle.acceleration = Float(TempMotionSaver[0])
TempVehicle.decceleration = Float(TempMotionSaver[1])
TempVehicle.maxspeed = Int(TempMotionSaver[2])
MotionTagFound = 1
EndIf


(Ich weiß: Die Parameter müssen jetzt immer in der gleichen reihenfolge stehen, aber sche** drauf Wink - für den Anfang reichts mir)

Markiert wird in der Funktion die Zeile "ReadParams[x] = ParamWithOutZoll[y]"... Ich hoffe ihr könnt mir helfen
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

ToeB

BeitragDi, Jan 03, 2012 21:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Also ich würde mir ja, anstatt die ganzen Befehle der XML-Datei einzeln abzufragen lieber direkt ein XML-Parser basteln welcher die Datei einließt und die Befehle und ihre Parameter in "Nodes" (Knoten) speichert und dann immer weiter verlinkt. Ich habe mal einen gebastelt, ist schon was länger her, aber vielleicht hilft es dir ja :
BlitzMax: [AUSKLAPPEN]


Type TXMLFile Final

Global TXMLFileList:TList = CreateList( )

Field TXMLFileListLink:TLink
Field TNodeList:TList
Field Filepath:String
Field Node:TNode

Method New( ) Final
TXMLFileListLink = TXMLFileList.AddLast( Self )
TNodeList = CreateList( )
EndMethod
Method Remove( ) Final
For Local tempNode:TNode = EachIn TNode.TNodeList
If tempNode.Info = Self Then tempNode.Remove( )
Next
TXMLFileListLink.Remove( )
EndMethod

Method GetNodeParameter:String( nodePath:String, nodeParameter:String )

Local tempNode:TNode = GetNode( nodePath )

If tempNode <> Null Then
'Print "XML GetNodeParameter "+tempNode.Name
Return tempNode.GetParameter( NodeParameter )
EndIf

Return ""

EndMethod

Method GetNodeValue:String( nodePath:String )

Local tempNode:TNode = GetNode( nodePath )

If tempNode <> Null Then
Return tempNode.Value
EndIf

Return ""

EndMethod

Method GetNodes:String[]( nodePath:String )

Local tempNode:TNode = GetNode( nodePath )

If tempNode <> Null Then
Local count:Int = 0
For Local checkNode:TNode = EachIn tempNode.NodeContainer
count = count + 1
Next
'Print "XML NODE "+tempNode.Name+" GetNodes "+count
Local NodeArray:String[ count+1 ]
count = 0
For checkNode = EachIn tempNode.NodeContainer
NodeArray[ count ] = checkNode.Name
count = count + 1
Next
Local NodeArray2:String[ count ]
For i = 0 To count-1
Local k:Int = 1
For Local j:Int = 0 To i-1
If NodeArray[i] = NodeArray[j] Then k = k + 1
Next
NodeArray2[i] = NodeArray[i]+"["+k+"]"
Next

Return NodeArray2
EndIf

Return Null

EndMethod

Method GetNode:TNode( nodePath:String )

nodePath = Replace( nodePath, "\", "/" )
If Right( nodePath, 1 ) <> "/" Then nodePath = nodePath + "/"
If Left( nodePath, 1 ) = "/" Then nodePath = Mid( nodePath, 2, Len( nodePath ) )

Local pathnodes:Int = 0, lastSlash:Int = 0
While Instr( nodePath, "/", lastSlash+1 )
pathnodes = pathnodes + 1
lastSlash = Instr( nodePath, "/", lastSlash+1 )
Wend

Local nodes:String[] = New String[ pathnodes+1 ]
Local nodeIndex:Int[] = New Int[ pathnodes+1 ]
lastSlash = 0

For Local i:Int = 0 To pathnodes-1
Local slash:Int = Instr( nodePath, "/", lastSlash+1 )
nodes[ i ] = Mid( nodePath, lastSlash+1, Slash - (lastSlash+1) )
If Right( nodes[ i ], 1 ) = "]" Then
nodeIndex[ i ] = Int( Mid( nodes[ i ], Instr( nodes[ i ], "[" )+1, Instr( nodes[ i ], "]" )-1 ) )
nodes[ i ] = Mid( nodes[ i ], 1, Instr( nodes[ i ], "[" )-1 )
Else
nodeIndex[ i ] = 1
EndIf

lastSlash = Slash
Next

Local aktNode:TNode = Null
Local NodeLevel:Int = 0
Local tempNode:TNode
Local NodePathLevel:Int = 0


For tempNode = EachIn TNode.TNodeList

If tempNode.Name = nodes[ NodePathLevel ] Then
NodeLevel = NodeLevel + 1
If NodeLevel = nodeIndex[ NodePathLevel ] Then
NodePathLevel = 1
Exit
EndIf
EndIf
Next

If NodePathLevel = 1 Then
Local getEnd:Int = 1
While (NodePathLevel < pathnodes)
NodeLevel = 0
Local get:Int = 0
'Print "XML CHECK "+nodes[ NodePathLevel ]+"("+nodeIndex[ NodePathLevel ]+") ("+nodePath+") : "
For Local checkNode:TNode = EachIn tempNode.NodeContainer
'Print "XML --- CHECK "+checkNode.Name+"("+(NodeLevel+1)+")"
If checkNode.Name = nodes[ NodePathLevel ] Then
NodeLevel = NodeLevel + 1
If NodeLevel = nodeIndex[ NodePathLevel ] Then
get = 1
Exit
EndIf
EndIf
Next
If get = 1 Then
NodePathLevel = NodePathLevel + 1
tempNode = checkNode
'Print "XML FOUND "+tempNode.name
Else
getEnd = 0
Exit
EndIf
Wend
If getEnd = 1 Then
Return tempNode
EndIf
EndIf
Return Null
EndMethod



End Type

Type TNode Final

Global TNodeList:TList = CreateList( )

Field TNodeListLink:TLink
Field Info:TXMLFile, InfoLink:TLink
Field LastNode:TNode, LastNodeLink:TLink
Field NodeContainer:TList
Field Name:String
Field ParameterLine:String, Parameter:String[], ParameterVal:String[], Parameters:Int
Field Value:String

Field tempOpen:Byte

Method New( ) Final
TNodeListLink = TNodeList.AddLast( Self )
NodeContainer = CreateList( )
EndMethod
Method Remove( ) Final
'Print "XML Delete NODE "+Name
TNodeListLink.Remove( )
InfoLink.Remove( )
If LastNodeLink <> Null Then LastNodeLink.Remove( )
LastNode = Null
Info = Null
TNodeContainer = Null
EndMethod

Method GetValue:String()
Return Value
EndMethod

Method GetParameter:String( nodeParameter:String )
For Local i:Int = 0 To Parameters-1
If Parameter[i] = nodeParameter Then Return ParameterVal[i]
Next
Return ""
EndMethod

Method GetPath:String( )
If LastNode <> Null Then
Local txt:String = LastNode.GetPath( )+"/"+Name
Return txt
EndIf
Return Name
End Method

End Type


Function OpenXML:TXMLFile( path:String )

Local Info:TXMLFile = (New TXMLFile)
Info.Filepath = path

Local InStream:TStream = ReadFile( Info.Filepath )
If InStream = Null Then
Info.Remove( )
Return Null
EndIf

Local LastNode:TNode = Null
'Local OpenNode:TNode = Null

While (Not Eof( inStream ))

Local line:String = Trim( ReadLine( inStream ) )
Local lowerLine:String = line

While (lowerLine <> "")

Local cBegin:Int = Instr( lowerline, "<" )
Local cEnd:Int = Instr( lowerline, ">" )
'Print "XML LINE "+lowerline
If cBegin > 0 And cEnd > 0 Then

Local cnPart:String = Mid( lowerline, cBegin+1, cEnd-cBegin-1 )
Local cPart:String = Lower( cnPart )
Local cNameEnd:Int = Instr( cPart, " " ) ; If cNameEnd = 0 Then cNameEnd = Len( cPart ) ; Else ; cNameEnd = cNameEnd - 1
Local cName:String =Mid( cPart, 1, cNameEnd )
Local cPar:String = Mid( cnPart, Len( cName )+1, Len( cPart ) )
Local cOpen:Byte = Byte( (Right( cPart, 1 ) <> "/") )

If cBegin > 1 And LastNode <> Null Then
Local cBef:String = Mid( lowerline, 1, cBegin-1 )
LastNode.Value = LastNode.Value + cBef
EndIf
lowerLine = Mid( lowerLine, cEnd+1, Len( lowerLine ) )
If LastNode <> Null Then
'Local dtxt:String = " LastNode "+LastNode.GetPath( )
'Print dtxt
EndIf
If Left( cPart, 1 ) <> "/" Then

Local Node:TNode = (New TNode)
Node.Info = Info
Node.InfoLink = Node.Info.TNodeList.Addlast( Node )
Node.LastNode = LastNode
Node.tempOpen = cOpen
Node.Name = cName
Node.ParameterLine = cPar
Node.Value = Mid( lowerline, 1, cBegin-1 )
Local debugtxt:String = "XML NODE "+Node.Name+" ADD "
If LastNode <> Null Then
Node.LastNodeLink = LastNode.NodeContainer.AddLast( Node )
debugtxt=debugtxt+"TO "+LastNode.Name+" "
EndIf
If Node.tempOpen = 1 Then
debugtxt = debugtxt +"OPENED "
EndIf
'Print debugtxt

If cEnd = 0 Then OpenNode = Node

If Node.tempOpen = 1 Then
LastNode = Node
EndIf

'Print "XML ADDNODE "+Node.Name+" VALUE "+Node.Value+" PARAMETER "+Node.ParameterLine

Else
If LastNode <> Null Then
cName = Mid( cName, 2, Len( cName ) )
If LastNode.Name = cName Then
LastNode.tempOpen = 0
LastNode.Value = LastNode.Value + Mid( lowerline, 1, cBegin-1 )
'Print "XML NODE "+LastNode.Name+" CLOSE PATH "+LastNode.GetPath( )'+" VALUE "+tempNode.Value+" PARAMETER "+tempNode.ParameterLine
LastNode = LastNode.LastNode
cOpen = 0
EndIf
EndIf
EndIf
Else
If LastNode <> Null Then
LastNode.Value = LastNode.Value + lowerline
EndIf
lowerline = ""
EndIf

Wend
Wend

For tempNode:TNode = EachIn TNode.TNodeList
debugtxt:String = "XML PARAMTERECHECK "+tempNode.Name+" "
If tempNode.Value <> "" Then
debugtxt = debugtxt + "VALUE "+tempnode.Value+" "
EndIf
If tempNode.ParameterLine <> "" Then

If Right( tempNode.ParameterLine, 1 ) = "/" Then
tempNode.ParameterLine = Mid( tempNode.ParameterLine, 1, Len( tempNode.ParameterLine )-1 )
EndIf
tempNode.ParameterLine = Trim( tempNode.ParameterLine )

Local parCount:Int = 0
Local lastPar:Int = 0
While Instr( tempNode.ParameterLine, "=", lastPar+1 )
parCount = parCount + 1
lastPar = Instr( tempNode.ParameterLine, "=", lastPar+1 )
Wend

If parCount > 0 Then
tempNode.Parameter = New String[ parCount+1 ]
tempNode.ParameterVal = New String[ parCount+1 ]
For Local i:Int = 0 To parCount-1
Local pMid:Int = Instr( tempNode.ParameterLine, "=" )
Local pName:String = Trim( Mid( tempNode.ParameterLine, 1, pMid-1 ) )
Local z1:Int = Instr( tempNode.ParameterLine, Chr(34) )
Local z2:Int = Instr( tempNode.ParameterLine, "'" )
If z1 < z2 Or (z1>0 And z2=0) Then
z2 = Instr( tempNode.ParameterLine, Chr(34), z1+1 )
Else
z1 = z2
z2 = Instr( tempNode.ParameterLine, "'", z1+1 )
DebugLog z1+","+z2
EndIf
Local pVal:String = Mid( tempNode.ParameterLine, z1+1, z2-z1-1 )
tempNode.Parameter[ i ] = pName
tempNode.ParameterVal[ i ] = pVal
tempNode.ParameterLine = Mid( tempNode.ParameterLine, z2+1, Len( tempNode.ParameterLine ) )
'debugtxt = debugtxt + "PAR "+tempNode.Parameter[i]+"("+tempNode.ParameterVal[i]+") "
Next
tempNode.Parameters = parCount
EndIf

EndIf
If tempNode.LastNode <> Null Then
debugtxt = debugtxt + "NODEPATH "+tempNode.GetPath( )+" "
EndIf
debugtxt = debugtxt + "CONTAINS "
Local first:Int = 1
For Local checkNode:TNode = EachIn tempNode.NodeContainer
If first = 0 Then
debugtxt = debugtxt +","
EndIf
debugtxt = debugtxt +checkNode.Name
first = 0
Next
'Print debugtxt
Next

CloseFile( InStream )
Return Info

End Function


Hiermit wird also eine Datei eingelesen (OpenXML). Diese wird dann in einem Type XMLFile gespeichert und dort kann jetzt nach Befehlen gesucht werden (XMLFile.GetNode(Path)). Path gibt hierbei an, um welchen Knoten es sich handelt. Für dein Beispiel wäre es, wenn du bspw. den Wert für die anzahl der Cylinders herausfinden möchtest, der hier : "vehicle\engine\cylinders". Hast du z.B. mehrere Nodes mit dem Selben Namen in der Selben ebene, also bspw. in der Ebene "Vehicle" mehrere Nodes die z.B. "Typ" heißen oder so, so kannst du ganz einfach angeben welche du meinst, in dem du hinter den Namen noch ein [ID] schreibst, also z.B. so :
"vehicle\typ[1]\name" oder "vehicle\typ[2]\name" etc.
Wenn du eine unbestimmte anzahl hast, kannst du auch zählen lassen, wie viele Nodes sich in der Ebene befinden, sie werden alle von GetNodes(path) in einem String-Array zurückgegeben als direkten Pfad, kann also in einer For-Eachin schleife durchlaufen werden.

Lg
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!

Xeres

Moderator

BeitragDi, Jan 03, 2012 22:49
Antworten mit Zitat
Benutzer-Profile anzeigen
BlitzMax: [AUSKLAPPEN]
While(x < NumberOfParams)
Das funktioniert nicht, wenn das Array, das du ausließt, eine andere Größe hat, als du anzunehmen beliebst.
Besser:
BlitzMax: [AUSKLAPPEN]
For Local i:Int=0 Until ParamWithOutZoll.Length


Wenn du die Datei XML nennst, solltest du dich einigermaßen an den Standard halten - Dinge wie
BlitzMax: [AUSKLAPPEN]
If(Left(Line, 7) = "<motion")
funktionieren, solange niemand Kommentare oder Verschachtelungen benutzt.
Wenn die Datei für Benutzer editierbar sein soll, wäre es gut, wenn du klar irgendwo angibst, was man nicht tun darf.
Am einfachsten wäre es dann, ein eigenes Textformat zu benutzen, was du sogar leichter auswerten könntest als XML.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
 

Macintosh

BeitragMi, Jan 04, 2012 0:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Zum parsen von String oder XML nutze ich immer eine Selbstgeschriene "Scanner" klasse. sowie NSScanner aus dem Cocoa framework.
So geht das meiner meinung nach am einfachsten und schnellsten.

Propellator

BeitragMi, Jan 04, 2012 1:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Ein alternativer Weg wäre Einstellungen in Lua-Scriptfiles zu speichern. BlitzMax hat einen Lua-Parser/Interpreter, und als voll ausgefleischte Scriptsprache gäbe es dem Benutzer auch die Möglichkeit gewisse Kontrollstrukturen in den Settings zu benutzen.
Ich habe schon andere Leute Lua als Werkzeug für Einstellungen benutzen sehen, jedoch selbst wenig Erfahrung damit.

MfG
Propellator - Alles andere ist irrelephant.
Elefanten sind die Könige der Antarktis.
 

CO2

ehemals "SirMO"

BeitragMi, Jan 11, 2012 21:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Gut, habe nun ein wenig rumexperimentiert, folgende (zufriedenstellende) Version ist herausgekommen:

BlitzMax: [AUSKLAPPEN]
Function CopyStringToChar:String(Text:String, Char:String)
Local returnstring:String = ""
Local Zaehler:Int = Instr(Text, Char, 0)
For x = 0 To (Zaehler - 2)
returnstring = returnstring + Text[x..x + 1]
Next
Return(returnstring)
End Function

Function DeleteStringToChar:String(Text:String, Char:String)
Local leftstring:String = ""
Local Zaehler:Int = Instr(Text, Char, 1)
leftstring = Text[Zaehler..Text.length]
Return(leftstring)
End Function

Function CopyStringFromChar:String(Text:String, Char:String)
Local returnstring:String = ""
Local Zaehler:Int = Instr(Text, Char, 0)
For x = Zaehler To (Text.length)
returnstring = returnstring + Text[x..x + 1]
Next
Return(returnstring)
End Function

Function GetParamBetweenTag:String(Line:String)
Local front:String = CopyStringToChar(Line, ">")
Local middle:String = CopyStringFromChar(Line, ">")
Local ReadParam:String = CopyStringToChar(middle, "<")
Return(ReadParam)
End Function

Function GetParamInTag(Line:String, ParamsCount:Int, ParamsSaver:String[])
Local TempString:String = Line
Local TempString2:String
For x = 0 To (ParamsCount - 1)
TempString = DeleteStringToChar(TempString, Chr(34))
ParamsSaver[x] = CopyStringToChar(TempString, Chr(34))
TempString2 = TempString
TempString2 = DeleteStringToChar(TempString, Chr(34))
TempString = TempString2
Next
End Function

Function SkipComment(File:TStream)
Local Line:String
Repeat
Line = ReadLine(File)
Until Instr(Line, "-->", 0)
End Function


Folgende Funktion sind enthalten:
Code: [AUSKLAPPEN]
-> CopyStringToChar(Text:String, Char:String)
     Parameter: -Text: Die Zeile in der bis zu einem Zeichen kopiert werden soll
                        -Char: Das Zeichen bis zu dem kopiert werden soll
     Beschreibung: Kopiert einen String bis zu einem Zeichen.
     Rückgabe: kopierter String

-> DeleteStringToChar(Text:string, Char:string)
     Parameter: -Text: Die Zeile in der bis zu einem Zeichen alles gelöscht werden soll
                        -Char: Das Zeichen bis zu dem gelöscht werden soll
     Beschreibung: Löscht einen String bis zu einem Zeichen
     Rückgabe: Übrig gebliebener String

-> CopyStringFromChar(Text:string, Char:string)
     Parameter: -Text: Die Zeile in der von einem Zeichen kopiert werden soll
                        -Char: Zeichen von dem kopiert werden soll
     Beschreibung: Kopiert einen String von einem Zeichen aus
     Rückgabe: kopierter String

-> GetParamBetweenTag(Line:String)
     Parameter: -Line: Die Zeile in der die Tags stehen (Wichtig: Zeile muss wie folgt aufgebaut sein: <TAGNAME>AUSZULESENDER-WERT</TAGNAME>, da sonst nichts zurückgegeben wird)
     Beschreibung: Liefert den Wert zwischen einem öffnenden und einem schließenden Tag aus.
     Rückgabe: Ausgelesener Wert

-> GetParamInTag(Line:string, ParamsCount:String, ParamsSaver:string[])
     Parameter: -Line: Die Zeile in der das Tag steht
                        -ParamsCount: Anzahl der auszulesenden Parameter (kleinster wert: 1)
                        -ParamsSaver: Array in dem die ausgelesenen Parameter gespeichert werden.
     Beschreibung: Liefert die Werte in einem Tag aus (Beispiel: <motion accelerate="0.0025" deccelerate="0.005" maxspeed="80"/>
     Rückgabe: Nichts (Ausgelesene Parameter werden in dem Array ParamsSaver gespeichert)


ich weiß, nichts besonderes, allerdings reicht es für meine zwecke. Mein xml-Parser sieht nun insgesamt wie folgt aus: BlitzMax: [AUSKLAPPEN]
'FOR VEHICLES
Type Vehicle
Field id:String
Field name:String
Field modelfile:String
Field acceleration:Float
Field decceleration:Float
Field maxspeed:Int
Field seat:Int
Field mpactive:Int
Field fueltype:Int
Field fuelusage:Float
Field fuelcapacity:Float
Field cylinder:Int
Field horsepower:Int
Field gearsystype:Int
Field gears:Int
Field turnpointx:Int
Field turnpointy:Int
Field exhaustpoints:TList
Field ddmactive:Int
Field ddmtype:Int
End Type
Type ExhaustPoint
Field PosX:Int
Field PosY:Int
End Type
Global Exhaustpoints:TList = CreateList()
Global Vehicles:TList = CreateList()

Function ReadVehicleDef(File:String)
'FormControlling
Local DefTagFound:Int = 0
Local VehiclesTagFound:Int = 0
Local VehicleTagFound:Int = 0
Local IDTagFound:Int = 0
Local NameTagFound:Int = 0
Local ModelTagFound:Int = 0
Local MotionTagFound:Int = 0
Local MPTagFound:Int = 0
Local SeatTagFound:Int = 0
Local EngineTagFound:Int = 0
Local FuelTagFound:Int = 0
Local CylinderTagFound:Int = 0
Local HorsePowerTagFound:Int = 0
Local GearSysTagFound:Int = 0
Local GearTagFound:Int = 0
Local CoordsTagFound:Int = 0
Local TurnPointTagFound:Int = 0
Local ExhaustSysTagFound:Int = 0
'###############

Local XMLData:TStream = ReadStream(File)
Local Line:String
Local TempVehicle:Vehicle = New Vehicle
Repeat
Line = Trim(ReadLine(XMLData))
If(Left(Line, 2) = "<?") 'Header
DefTagFound = 1
Continue
EndIf
If(Left(Line, 4) = "<!--") 'Kommentar
SkipComment(XMLData)
EndIf
If(Left(Line, 9) = "<vehicles") 'HauptBlock
Local TempNumOfCars:String[100]
GetParamInTag(Line, 1, TempNumOfCars)
VehiclesTagFound = 1
EndIf
If(Left(Line, 8) = "<vehicle") 'Neue Instanz
VehicleTagFound = 1
Continue
EndIf
If(Left(Line, 3) = "<id") 'ID Definieren
TempVehicle.id = GetParamBetweenTag(Line)
IDTagFound = 1
EndIf
If(Left(Line, 5) = "<name") 'Name Definieren
TempVehicle.name = GetParamBetweenTag(Line)
NameTagFound = 1
EndIf
If(Left(Line, 6) = "<model") 'ModelFile
Local TempModelFile:String[100]
GetParamInTag(Line, 1, TempModelFile)
TempVehicle.modelfile = TempModelFile[0]
ModelTagFound = 1
EndIf
If(Left(Line, 7) = "<motion") 'Bewegung
Local TempMotionSaver:String[100]
GetParamInTag(Line, 3, TempMotionSaver)
TempVehicle.acceleration = Float(TempMotionSaver[0])
TempVehicle.decceleration = Float(TempMotionSaver[1])
TempVehicle.maxspeed = Int(TempMotionSaver[2])
MotionTagFound = 1
EndIf
If(Left(Line, 12) = "<multiplayer") 'Multiplayer-Daten
Local TempMultipSaver:String[100]
GetParamInTag(Line, 1, TempMultipSaver)
If(TempMultipSaver[0] = "True" Or TempMultipSaver[0] = "true")
TempVehicle.mpactive = 1
Else
TempVehicle.mpactive = 0
EndIf
MPTagFound = 1
EndIf
If(Left(Line, 5) = "<seat") 'Anzahl der Sitze
TempVehicle.seat = Int(GetParamBetweenTag(Line))
SeatTagFound = 1
EndIf
If(Left(Line, 7) = "<engine") 'Motor-Daten
EngineTagFound = 1
Continue
EndIf
If(Left(Line, 5) = "<fuel") 'Kraftstoff-Daten
Local TempFuelData:String[100]
GetParamInTag(Line, 3, TempFuelData)
TempVehicle.fueltype = Int(TempFuelData[0])
TempVehicle.fuelusage = Float(TempFuelData[1])
TempVehicle.fuelcapacity = Float(TempFuelData[2])
FuelTagFound = 1
EndIf
If(Left(Line, 9) = "<cylinder") 'Anzahl Zylinder
TempVehicle.cylinder = Int(GetParamBetweenTag(Line))
CylinderTagFound = 1
EndIf
If(Left(Line, 11) = "<horsepower") 'PferdeStärke
TempVehicle.horsepower = Int(GetParamBetweenTag(Line))
HorsePowerTagFound = 1
EndIf
If(Left(Line, 11) = "<gearsystem") 'Gangschaltung
Local TempGearSys:String[100]
GetParamInTag(Line, 1, TempGearSys)
TempVehicle.gearsystype = Int(TempGearSys[0])
GearSysTagFound = 1
EndIf
If(Left(Line, 6) = "<gears") 'Gänge
TempVehicle.gears = Int(GetParamBetweenTag(Line))
GearTagFound = 1
EndIf
If(Left(Line, 7) = "<coords")
CoordsTagFound = 1
Continue
EndIf
If(Left(Line, 10) = "<turnpoint")
Local TempTurnPoints:String[100]
GetParamInTag(Line, 2, TempTurnPoints)
TempVehicle.turnpointx = Int(TempTurnPoints[0])
TempVehicle.turnpointy = Int(TempTurnPoints[1])
TurnPointTagFound = 1
EndIf
If(Left(Line, 14) = "<exhaustsystem")
Local TempExhSys:String[100]
Local TempExhPoint:String[100]
Local TempDefLine:String
GetParamInTag(Line, 1, TempExhSys)
TempExhSys[0] = Int(TempExhSys[0]) - 1

Print Int(TempExhSys[0])
If(Int(TempExhSys[0]) > 0)
For x = 0 To Int(TempExhSys[0])
TempDefLine = ReadLine(XMLData)
If(TempDefLine = "")
x = x - 1
Continue
Else
GetParamInTag(TempDefLine, 2, TempExhPoint)
Local NewExhPoint:ExhaustPoint = New ExhaustPoint
NewExhPoint.PosX = Int(TempExhPoint[0])
NewExhPoint.PosY = Int(TempExhPoint[1])
ListAddLast(Exhaustpoints, NewExhPoint)
EndIf
Next
TempVehicle.exhaustpoints = Exhaustpoints
EndIf
ExhaustSysTagFound = 1
EndIf
If(Left(Line, 4) = "<ddm")
Local TempDDM:String[100]
GetParamInTag(Line, 2, TempDDM)
If(TempDDM[0] = "true")
TempVehicle.ddmactive = 1
Else
TempVehicle.ddmactive = 0
EndIf
Select(TempDDM[1])
Case "std"
TempVehicle.ddmtype = 1
Case "adv"
TempVehicle.ddmtype = 2
Case "ind"
TempVehicle.ddmtype = 3
Default
RuntimeError("Error in XML-Data: Wrong Expression found!")
End Select
EndIf
If(Line = "")
Continue
EndIf
Until Eof(XMLData)

If(DefTagFound = 0 Or VehiclesTagFound = 0 Or VehicleTagFound = 0 Or IDTagFound = 0 Or NameTagFound = 0 Or ModelTagFound = 0 Or MotionTagFound = 0 Or MPTagFound = 0 Or SeatTagFound = 0 Or EngineTagFound = 0 Or CylinderTagFound = 0 Or HorsePowerTagFound = 0 Or GearSysTagFound = 0 Or GearTagFound = 0 Or CoordsTagFound = 0 Or ExhaustSysTagFound = 0)
RuntimeError("Error in XML-Data: Tag Missing!")
Else
ListAddLast(Vehicles, TempVehicle)
EndIf

CloseFile(XMLData)
End Function
'##############

'FOR ALL
Function CopyStringToChar:String(Text:String, Char:String)
Local returnstring:String = ""
Local Zaehler:Int = Instr(Text, Char, 0)
For x = 0 To (Zaehler - 2)
returnstring = returnstring + Text[x..x + 1]
Next
Return(returnstring)
End Function

Function DeleteStringToChar:String(Text:String, Char:String)
Local leftstring:String = ""
Local Zaehler:Int = Instr(Text, Char, 1)
leftstring = Text[Zaehler..Text.length]
Return(leftstring)
End Function

Function CopyStringFromChar:String(Text:String, Char:String)
Local returnstring:String = ""
Local Zaehler:Int = Instr(Text, Char, 0)
For x = Zaehler To (Text.length)
returnstring = returnstring + Text[x..x + 1]
Next
Return(returnstring)
End Function

Function GetParamBetweenTag:String(Line:String)
Local front:String = CopyStringToChar(Line, ">")
Local middle:String = CopyStringFromChar(Line, ">")
Local ReadParam:String = CopyStringToChar(middle, "<")
Return(ReadParam)
End Function

Function GetParamInTag(Line:String, ParamsCount:Int, ParamsSaver:String[])
Local TempString:String = Line
Local TempString2:String
For x = 0 To (ParamsCount - 1)
TempString = DeleteStringToChar(TempString, Chr(34))
ParamsSaver[x] = CopyStringToChar(TempString, Chr(34))
TempString2 = TempString
TempString2 = DeleteStringToChar(TempString, Chr(34))
TempString = TempString2
Next
End Function

Function SkipComment(File:TStream)
Local Line:String
Repeat
Line = ReadLine(File)
Until Instr(Line, "-->", 0)
End Function
'##############


Das XML-Format auf dem aufgebaut wurde sieht so aus: Code: [AUSKLAPPEN]
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<!--
   Author: Marius Otto, CO2 Software
   File: vehicles.xml
   Date: 03.01.2012
-->

<vehicles count="1">
   <!--
   #####################################################################################
   FORM:
   <vehicle>
      <id>$CLASS_ID$</id>
      <name>NAME</name>
      <model file="[FILENAME]"/>
      <motion accelerate="[VALUE]" deccelerate="[VALUE]" maxspeed="[VALUE]"/>
      <mutliplayer active="[BOOL]">
         <seat>VALUE</seat>
      </multiplayer>
      <engine>
         <fuel type="[TYPE*]" usage="[VALUE]" capacity="[VALUE]"/>
         <cylinder>VALUE</cylinder>
         <horsepower>VALUE</horsepower>
         <gearsystem type="[TYPE**]">
            <gears>VALUE</gears>
         </gearsystem>
      </engine>
      <coords>
         <turnpoint x="[POSITION]" y="[POSITION]"/>
         <exhaustsystem count="[VALUE***]">
            <exhaustpoint x="[POSITION]" y="[position]"/>
         </exhaustsystem>
      </coords>
      <ddm active="[BOOL]" type="[TYPE****]">
   </vehicle>
   #####################################################################################
   
   - *) FUEL TYPES: 1 = gas; 2 = diesel; 3 = kerosene
   - **) GEARSYSTEM TYPES: 1 = automatic; 2 = semi-automatic; 3 = only manual
   - ***) This value describes how many exhaustpoints are needed, e.g.: If this is "2" you need to define 2 exhaustpoints
   - ****) DDM-TYPES: "std" = standart; "adv" = advanced
   -->
   <vehicle>
      <id>$VEH_AMBULANCE$</id>
      <name>Krankenwagen</name>
      <model file="mod\ambulance.2dm"/>
      <motion accelerate="0.0025" deccelerate="0.005" maxspeed="80"/>
      <multiplayer active="true">
         <seat>6</seat>
      </multiplayer>
      <engine>
         <fuel type="2" usage="0.002" capacity="85"/>
         <cylinder>6</cylinder>
         <horsepower>125</horsepower>
         <gearsystem type="1">
            <gears>4</gears>
         </gearsystem>
      </engine>
      <coords>
         <turnpoint x="42" y="160"/>
         <exhaustsystem count="1">
            <exhaustpoint x="14" y="199"/>
         </exhaustsystem>
      </coords>
      <ddm active="true" type="std"/>
   </vehicle>
</vehicles>


EDIT: Zu den Tipps mit den Modulen: Die sind mir alle zu groß, ich brauche einen "leichten" xml-parser (im übrigen muss der auch nicht viel können). Smile

mfG,
CO2
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group