webForumDet fria alternativet

Strukturhjälp med klassindelning

PHP

30 svar · 785 visningar · startad av SDCd

Medlem sedan jan. 2001795 inlägg
Frågan#1

Har nu knåpat ihop ett skript som läser in en XML-fil, uppdaterar med ny info och skriver tillbaka det till filen.

Tänkte ge mig in på lite snygg uppdelning av XML-funktioner, och skulle behöva lite styrning i mitt tänkande.

Det jag tänkt mig är att ha skapa ett skript för att uppdatera en XML-fil.

Jag hade tänkt mig att lägga själva parserfunktionen i en egen inkluderingsfil för att kunna använda mig av den vid olika utseende av XMLfiler.

Sen hade jag tänkt mig en andra inkluderingsfil där jag lägger de andra filspecifika XML-funktionerna för att läsa in TAGGAR , ID och DATA i en variabel och sedan skicka den till den första inkluderingsfilen för att skriva till samma fil, (också en funktion som är oberoende av utseende på XML-filen).

Den andra filen skall sedan inkluderas på skriptsidan där variablerna kommer från en FORM.

Tänkte detta vore ett bra tillfälle att ta en stor tugga ur OOP delen av PHP.

Just nu känns det som tuggan hamnat i fel strupe :) och jag undrar om det är någon vänlig själ som har lust att ge mig lite styrning i hur jag lägger upp det hela.

Medlem sedan mars 20007 896 inlägg
#2

PHP-OOP är helt rätt tänkt, det gör det hela mycket snyggare och enklare. Jag har lite svårt att förstå hur du menar, men jag kan lägga lite tankar här:

Först och främst bör du modellera lite över vilka klasser du kan tänkas behöva, det görs bäst på vanligt papper med en blyertspenna. De klasser jag spontant kan tänka mig är följande:
XMLDoc
XMLElement
XMLAttribute

XMLDoc hanterar hela dokumentet, som innehåller element ( XMLElement ) som kan innehålla attribut, värden och andra element - men inte behöver göra det.

Metoder för de olika klasserna:

För XMLDoc:
void XMLDoc->createDoc( [ string filename ] ) // Skapar nytt dokument
void XMLDoc->openDoc( string filename ) // Öppnar befintligt dokument
void XMLDoc->saveDoc( [ string filename ] ) // Sparar dokumentet
XMLElement XMLDoc->getRoot()
void XMLDoc->append( XMLElement element ) // Lägger till ett XMLElement i slutet av dokumentet

För XMLElement:
void XMLElement->append( XMLElement element ) // Lägger till ett XMLElement i slutet av elementet
string XMLElement->xml() // Returnerar värde på elementet, kan vara andra element också
void XMLElement->value( string value ) // Sätter ett nytt värde på elementet
void XMLElement->addAttribute( XMLAttribute attribute ) // Lägger till ett attribut till elementet
XMLAttribute XMLElement->getAttribute( string attribute-name ) // Hämtar attribut-värde från angivet attribut

För XMLAttribute:
void XMLAttribute->setName( string name ) // Sätter ett namn på attributet
string XMLAttribute->getName() // Returnerar namnet på attributet
void XMLAttribute->setValue( string value ) // Sätter ett värde på attributet
string XMLAttribute->getValue() // Returnerar värdet på attributet

Självklart finns med många fler metoder som borde vara med, men lite får du tänka själv. ;)

Säg till om du behöver mer hjälp, det är ju rätt krångligt att skapa en bra fungerande XML-parser i PHP - jag har försökt. :)

Såg att du i en tidigare tråd frågade efter en fungerande XML-parser, inbyggd eller extern. Det finns ju alltid XML-parserfunktionerna i PHP, men de kan vara lite kluriga. Jag har nog ett fungerande exempel om du vill veta mer... Ska leta lite på hårddisken. Fråga! :)

Medlem sedan jan. 2001795 inlägg
#3

Aha! Helgpermis? :)

Mitt första inlägg baserar sig på att jag använt mig av de inbyggda XML-parserfunktionerna i PHP, och det fungerar bra. Jag har dock all kod i samma fil.

De filer jag tänkt jobba med har en färdig elementstruktur + tillhörande attribut. Men för att kunna i framtiden addera stöd för uppdatering av andra elementstrukturer tänkte jag mig en uppdelning på följande sätt, och det är här jag undrar om jag tänker rätt

Det jag tänkte mig i detta stadium var att dela upp de olika funktionerna så att till exempel:

Inkluderingsfil 1.
Generell new_xml_parser() funktion.
Generell skriva_till_fil() funktion.

Denna fil tänkte jag inkludera i

Inkluderingsfil 2. där jag tänkt lägga de elementspecifika funktionerna
startElement()
endElement()
characterData()
Dessutom funktioner som ärver från de funktioner som ligger i inkluderingsfil1.

Nu är detta väldigt basic, men jag hoppas du förstår var jag är på väg. Om jag vid ett senare tillfälle skulle vilja uppdatera en annan XML fil med annorlunda elementstruktur kan jag då använda mig av inkluderingsfil1 i den med.

Jag skulle alltså vilja kunna inkludera inkluderingsfil2 i ett skript, skicka filnamn, attribut och data och filen uppdateras med dessa variabler.

Är mitt uppdelningstänkande helt åt fanders?

Medlem sedan mars 20007 896 inlägg
#4

Aha! Helgpermis?

Si! Kom för någon timme sen. :)

Nej, jag tycker inte att ditt uppdelningstänkande är åt fanders - utan åt andra hållet. Det låter bra, speciellt med att du ärver från en annan klass för att skapa statiska metoder. Men här tycker jag att det bör kunna förbättras... Går det inte att skapa dynamiska metoder startElement(), endElement() och characterData()? Det beror ju egentligen på hur komplex XML-strukturen är, men bör väl gå att komma runt? T.ex. att passa arrayer som attribut till någon metod som lagrar den i en instans-variabel i klassen.

Jag förstår mycket bättre nu, men ge gärna lite kod-exempel så kanske jag kan ge ännu mer hjälp. :)

Medlem sedan jan. 2001795 inlägg
#5

Si! Kom för någon timme sen.

Hur många pinnar till muck? :)

Jag förstår ditt tankesätt med att även göra dynamiska metoder av elementhanterarna. Jag var inne på en skiss där jag tänkte mig "tomma" XML-dokument som fungerar som mallar för hur det förväntade dokumentet ser ut.
Eftersom jag är ute på okänd OOP-mark siktade jag dock i första läget på den "semi"-dynamiska uppdelningen jag beskrev tidigare :)
När det gäller kod är jag fortfarande på papper&penna stadiet, så det är inte så mycket att visa. Har du några generella class-kodsnuttar att studera tar jag dock emot dem med öppna armar

Medlem sedan mars 20007 896 inlägg
#6

Hur många pinnar till muck?

Tja, en ca 200. :e :)

Fast med tomma XML-dokument som mallar får du också semi-dynamik, eftersom att du inte kan "möblera om" dem, så att säga. Just skrivningen av XML måste man väl hålla på det stadiet, men som jag förstod det ville du även läsa XML-dokument? Där kan man vinna på att skriva dynamiskt. Jag har tyvärr inga färdiga exempel på just det här, och jag ska iväg nu. Men i morgon borde jag kunna slänga ihop något av det jag tänker på, plus kanske lite mer som jag kommer på. Hoppas att du inte är så otålig nu... I'll be back... :)

Medlem sedan jan. 2001795 inlägg
#7

Ingen fara. Förstår att du skall ut och fira friheten :)
Det är ju en ordentlig pinnhög du har kvar ;)
Ha det skoj!

Medlem sedan mars 20007 896 inlägg
#8

Ok, nu har jag suttit och fifflat lite - och kommit fram till följande två klasser ( SPiNXML.txt ). Jag vet ännu inte om de fungerar, jag har ingen server med PHP så att jag kan testa, men jag skrev ihop en test-fil ( SPiNXML_TestPilot.txt ) som borde göra det jag vill. :)

Det här är alltså bara grunden, när du vill skriva statiskt får du skapa en till klass som fyller upp ett dokument med det du vill.

Hoppas nu att det var något sånt här du var ute efter.

MvH,

Medlem sedan mars 20007 896 inlägg
#9

Här kommer fil två.

Medlem sedan jan. 2001795 inlägg
#10

Tack så väldigt mycket för detta!
Skall sätta mig och studera koden, finns säkert en hel del jag kan använda, inte minst i utbildningssyfte.

Kanontack!

Medlem sedan jan. 2001795 inlägg
#11

Har lite problem med SPiN:s fina kodexempel. Funktionen:

function addTag ( $theName ) {
//		$tag = new SPiNXMLTag();
		$tag = $this->newTag();
		$tag->setName( $theName );
		
		$this->tagParent = &$this->xmlTag;
		
		array_push( $this->tagTags, $tag );
		$this->xmlTag = $tag;
	}

På raden:

$tag = $this->newTag();

anropas funktionen newTag(). Den funktionen är inte skriven och jag får inte till det riktigt med mina begränsade OOP kunskaper.
Jag försökte byta ut den mot den bortkommenterade raden men får då dels varningen:

Warning: First argument to array_push() needs to be an array in SPiNXML.inc on line 132

Och dels error:

Fatal error: Call to a member function on a non-object in SPiNXML.inc on line 32

Har inte klistrat in mer kod här eftersom all kod finns i SPiN:s bifogade filer.

Eftersom SPiN är och springer hinderbana :) kanske någon annan vänlig själ kan tipsa, annars får jag vänta tills SPiN får på sig permisuniformen nästa gång.

Hittade även en missad parentes på rad 70

	$this->xmlData .= ">" . trim( $theRootTag->getContent()) . 
"</" . $theRootTag->getName() . ">\n";

trim funktionen var inte avslutad.

Medlem sedan mars 20007 896 inlägg
#12

Ingen hinderbana och ingen permisuniform... Jag åker i M90. ;)

Det var ju lite skumt att du inte lyckades med ditt försök... Det borde ju fungera. :q

Såg ditt dokument ut så här när du var klar?

Medlem sedan jan. 2001795 inlägg
#13

Ingen hinderbana? Ack ack, hoppas inte ryssen kommer :)

Laddade ner din nya fil och provade med den.
Det som händer då är:
I din testpilot anropar du en funktion addData() som jag tycker borde vara addContent().
Jag får dessutom felmeddelande: Att första argumentet till array_push() skall vara en array.
Det verkar inte som konstruktorn körs när jag anropar

$tag = new SPiNXMLTag();

Om jag deklarerar variabeln $tagTags som en array i klassdeklarationen får jag bort felmeddelandena.

Gör jag detta får jag felmeddelande i funktionen getAttributes().
Raden:

return $this->theAttributes;

Borde inte den funktionen returnera:

return $this->tagAttributes;

När gjort detta får jag felmeddelandet:

Call to undefined function createxml() in spinxml.inc on line 64
Medlem sedan mars 20007 896 inlägg
#14

Uff, nu har jag suttit och pillat i filerna för att se om det blir bättre. Jag har säkert glömt något, eller skrivit något fel - kom ju hem idag och är trött. :x

Här är SPiNXML.txt åtminstone:

Medlem sedan mars 20007 896 inlägg
#15

Och här är SPiXML_TestPilot.txt:

Medlem sedan jan. 2001795 inlägg
#16

Ta det lungt, efter en vecka i grönt tycker jag du skall luta dig tillbaka och softa :)

När det gäller dina filer såg jag vid en snabb överblick:
I första filen: Du har skapat två nya klasser.

class SPiNXMLAttributeList

class SPiNXMLAttribute

I den första har du koden:

		$xmlAttribute = new SPiNXMLAttribute();
		$xmlAttribute->start();

klassen SPiNXMLAttribute(); har ingen startfunktion för initiering.

Jag skall, när jag får lite mer tid titta nogrannare på koden för att se hur du tänker.
En fråga bara. Hur kommer det sig att du ändrat klasserna från att ha en konstruktor till att ha startfunktioner?

Medlem sedan mars 20007 896 inlägg
#17

Det var bara för att det inte verkade som att konstruktorerna kördes, för att se om det fungerade. Det är mycket fult gjort, och visst kan man göra annorlunda - men det här var det enklaste alternativet.

Attribut-klasserna lade jag till bara för att göra det lite snyggare och lättare att förstå. Istället för att returnera en array med arrayer med attributnamn och attributvärde ( Se ex. 1 ) så använder jag nu en attributlista som lagrar attributobjekt som innehåller namn och värden ( Se ex. 2 ), där man snabbt kommer åt ett attributvärde via SPiNXMLAttributList::getByName().
Ex. 1

$arrayFörAttribut = array();
$arrayAttribut1 = array( "AttrNamn", "AttrVärde" );
array_push( $arrayFörAttribut, $arrayAttribut1 );

$arrayAttribut2 = array( "AttrNamn", "AttrVärde" );
array_push( $arrayFörAttribut, $arrayAttribut2 );

foreach( $arrayFörAttribut as $arrayAttribute ) {
     if( $arrayAttribute[ 0 ] == "AttrNamn" )
          echo $arrayAttribute[ 1 ];
}

Ex. 2

$attrList = new SPiNXMLAttributeList();
$attrList->start();

$attr = new SPiNXMLAttribute();
$attr->setName( "AttrNamn" );
$attr->setValue( "AttrVärde" );
$attrList->add( $attr );

$attr->setName( "AttrNamn" );
$attr->setValue( "AttrVärde" );
$attrList->add( $attr );

echo $attrList->getByName( "attrNamn" );

Snyggare och enklare, tycker jag.

Jag bifogar uppdaterade filer...

Medlem sedan mars 20007 896 inlägg
#18

SPiNXML_TestPilot.txt

Medlem sedan jan. 2001795 inlägg
#19

Jag öser på med lite saker här.

Du har skapat en funktion som heter

function setAttribute( $tagAttributeName, $tagAttributeValue )

Den anropar du i elementStart() med

$this->xmlTag->setAttributes( $theAttributes )

Förstår inte riktigt din tanke med detta. $theAttributes är väl en array som består av attributnamn/attributvärde?

Medlem sedan jan. 2001795 inlägg
#20

Ändrade ovanstående funktion till

function setAttribute( $theAttributes )

och sedan innuti funktionen

while (list($tagAttributeName, $tagAttributeValue) = each($theAttributes)) 
{
       	$this->tagAttributeList->apply( $tagAttributeName, $tagAttributeValue );   
}

Ändrade även i testpiloten och la först AttributNamn och AttributVärde i en array som jag sedan skickar till ovan nämda funktion.

La även in en koll i elementStart()

if (sizeof($theAttributes))
{
	$this->xmlTag->setAttributes( $theAttributes );
}

så att setAttributes anropas med en array.

Är jag på väg åt rätt håll?

Då dyker nästa problem upp, :) funktionen createXML() anropar sig själv

if( count( array_keys( $xmlTagList ) ) > 0 && trim( $theRootTag->getContent() ) == "" ) {
	$this->xmlData .= ">\n";
			
	createXML( array_pop( $xmlTagList ), $xmlPre . "\t" );
}

och det får jag felmeddelande på.

Fatal error: Call to undefined function: createxml() in spinxml_new.inc on line 72

Får se om jag lyckas klura ut den tills SPiN kommer hem på permis :)

296 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
140 ms — deklarationer (db)
0 ms — hämta statistik (cache)
153 ms — hämta tråd, inlägg och bilagor (db)
116 ms — ändringar (db)