Problem z wczytaniem XML

0

Witam

Mam plik XML:

<?xml version="1.0" encoding="UTF-8"?>
<btio>
	<funkcja nazwa="cin" opis="Wczytanie danych do zmiennej">cin << %z;</funkcja>
	<funkcja nazwa="cout" opis="Wypisanie danych ze zmiennej">cout >> %z;</funkcja>
</btio>

i kod programu:

NodeGowna:= XML.ChildNodes.FindNode('btio');
  if Assigned(NodeGowna) then
  begin
	XMLNode:= NodeGowna.ChildNodes.FindNode('funkcja');
	while XMLNode <> nil do
	begin
	  l:= ListView1.Items.Add;
	  l.Caption:= XMLNode.AttributeNodes['nazwa'].Text;
	  l.SubItems.Add(XMLNode.AttributeNodes['opis'].Text);
	  ShowMessage(XMLNode.NodeValue);
	  //l.SubItems.Add(XMLNode.NodeValue);
	  XMLNode:= XMLNode.NextSibling;
	end;
  end;

wysypuje się na ShowMessage()

Element does not contain a single text node

Chciałbym odczytać wartość gałęzi czyli "cin << %z;"

0

Odpiszę Tobie to samo co na innym forum:

Nie znam się dobrze na TXMLDocument. Ponieważ mam Delphi 7 - Personal i jak się da to w
swoim kodzie używam zewnętrznego parsera XML. A konkretnie modułu spkxmlparser jest do
pobrania z http://spook.freshsite.pl/files/download/spkxmlparser.zip ten kod poniżej działa ok:

//...
uses
  spkxmlparser;

var
  XML : TSpkXMLParser;
  MainNode, XMLNode : TSpkXMLNode;

procedure TForm1.Button1Click(Sender: TObject);
var
  I : integer;
  ListItem : TListItem;
begin
  XML := TSpkXMLParser.Create;
  XML.LoadFromFile('test.xml');
  MainNode := XML.NodeByName['btio', False];
  if MainNode = nil then
  begin
    MessageBox(Application.Handle, PChar('Nieprawidłowy format pliku XML!'),
    PChar(Application.Title), MB_OK or MB_ICONERROR);
    XML.Free;
    Exit;
  end;
  ListView1.Items.Clear;
  for I := 0 to MainNode.Count - 1 do
  begin
    ListItem := ListView1.Items.Add;
    XmlNode := MainNode.NodeByIndex[I];
    Listitem.Caption := XMLNode.Parameters.ParamByName['nazwa', False].Value;
    ListItem.SubItems.Add(XMLNode.Parameters.ParamByName['opis', False].Value);
  end;
  XML.Free;
end;
0

Ja bym to napisał tak:

var XML : TXMLDocument;
    NodeGowna : IXMLNode;
    XMLNode : IXMLNode;
begin
    try
        XML:=TXMLDocument.Create(Self);
        XML.FileName:=ExtractFilePath(ParamStr(0))+'plik.xml';
        XML.Active:=TRUE;
        NodeGowna:= XML.ChildNodes.FindNode('btio');
        if Assigned(NodeGowna) then begin
            XMLNode:= NodeGowna.ChildNodes.FindNode('funkcja');
            while XMLNode <> nil do begin
              //l:= ListView1.Items.Add;
              //l.Caption:= XMLNode.AttributeNodes['nazwa'].Text;
              //l.SubItems.Add(XMLNode.AttributeNodes['opis'].Text);
              ShowMessage(XMLNode.Text);
              //l.SubItems.Add(XMLNode.NodeValue);
              XMLNode:= XMLNode.NextSibling;
            end;
        end;
    finally
        XML.Free;
    end;
end;
0
<?xml version="1.0" encoding="UTF-8"?> <btio> <funkcja nazwa="cin" opis="Wczytanie danych do zmiennej">cin << %z;</funkcja> <funkcja nazwa="cout" opis="Wypisanie danych ze zmiennej">cout >> %z;</funkcja> </btio>

To nie zadziała bo nie ma prawa zadziałać.
Powyższy tekst nie jest prawidłowym XML-em. Tagi są źle zamknięte i wstąpił w wartości cudzysłów.
Nazwy sekcji również powinny być unikalne
Odsyłam do http://www.w3schools.com/xmL/xml_syntax.asp

<?xml version="1.0" encoding="UTF-8"?> <btio> <funkcja nazwa="cin" opis="Wczytanie danych do zmiennej&quot;">cin << %z;" /> <funkcja2 nazwa="cout" opis="Wypisanie danych ze zmiennej&quot;">cout >> %z;" /> </btio>
0

@gamestone:
Ten XML akurat jest prawidłowy. Twój też, ale ma zupełnie inną strukturę.
Jest pewna różnica pomiędzy <element attr="value" /> a <element>value</element>. I obydwa z tych sposobów zapisu są poprawne, ale inne. Nikt nie broni tez ich mieszać, do przechowywania pewnych danych lepiej nadają się węzły tekstowe po prostu, a nie atrybuty.

Nazwy sekcji również powinny być unikalne

Aha. Czyli w takim XHTML to nie mogę użyć dwóch elementów pod rząd. A w całym dokumencie XHTML może być tylko jedno ? XML przewiduje tylko jeden element główny (tutaj: btio), ale potem może już być wiele elementów o takiej samej nazwie, z takimi samymi albo i różnymi parametrami.

0

gamestone, przeczytaj ze zrozumieniem jeszcze raz dokumentację do której linka dajesz.
Bo wszystko co napisałeś jest bzdurą.

0

Gamestone przyjacielu sympatyczny, natenczas, tudzież, aczkolwiek, jakoby, bynajmniej. A czy ty w ogóle uruchomiłeś kod, który wkleiłem ?

Bo ja muszę ci się przyznać w sekrecie zapisałem sobie ten XML, który podał djmentos do pliku tekstowego z rozszerzeniem XML, a nastepnie w Button1Click wprowadziłem kod taki, jaki podałem w poprzednim poście.

I tutaj niespodzanka. Podejrzewam, że cię zaskoczę. Ale o dziwo działa i jeszcze jedna niespodzianka - pokazuje dokładnie to, czego djmentos się spodziewa ;)

0

A jak rozwiązać problem użycia ww. odczytu pliku XML w sterowniku DLL w Trubo Delphi? Przy użyciu

XML:=TXMLDocument.Create(self);

otrzymuję komunikat błędu:

[Pascal Error] ... There is no overloaded version of 'Create' that can be called with these arguments

Bardzo proszę o pomoc.

0

Metoda Create z klasy TXMDocument ma inną, być może pustą, listę parametrów.
Poszukaj w dokumentacji co ma być parametrem metody.

0

W dokumentacji metody Create znalazłem:

constructor TXMLDocument.Create(AOwner: TComponent);
begin
  { Need to have this to make this constructor visible to C++ classes }
  inherited;
end;

ale i tak nie wiem jak rozwiązać ten problem...

0

zrób tak:

XML:=TXMLDocument.Create(nil);

tylko że wtedy obiekt nie będzie miał ownera i sam musisz zadbać o jego zwolnienie.

Z dokumentacji wynika że ownerem może być obiekt klasy TComponent. Ty użyłeś self, nie wiadomo jaka klasa kryje się pod self

0

Próbowałem już tego i aplikacja się zawiesza, przez co muszę ją zamykać w *Procesach *systemowych ;/ a jak mogę później go zwolnić gdy nie ma ownera?

0

Wwklej kod całej metody albo i klasy, wtedy będzie łatwiej pomóc.
Sprawdź czy w Turbo Delphi istnieje interfejs IXMLDocument

0
var
  XML : TXMLDocument;
  NodeMain : IXMLNode;
  XMLNode : IXMLNode;
begin
    try
        XML:=TXMLDocument.Create(self);
        XML.FileName:='C:\prod.xml';
        XML.Active:=TRUE;
        NodeMain:= XML.ChildNodes.FindNode('product');
        if Assigned(NodeMain) then begin
            XMLNode:= NodeMain.ChildNodes.FindNode('id');
            while XMLNode <> nil do begin

              ShowMessage(XMLNode.Text);

              XMLNode:= XMLNode.NextSibling;
            end;
        end;
    finally
        FreeAndNil(XML);
        XML.Free;
    end;
end ;

Ten kod jest wcześniej podany i lekko przeze mnie przerobiony. Metoda jest wywoływana i dziedziczona po interfejsie, ale on nic tak naprawdę nie wnosi. Kod działa w aplikacji okienkowej (desktopowej), a w konsoli już nie. Więc czy to robimy w konsoli czy w sterowniku DLL to dzieje się to samo. Kodu interfejsu i jego method nie mogę tutaj wkleić, gdyż zajmuje za dużo miejsca.

2

spróbuj tak, intefrejsów nie musisz zwalniać

var
  XML: IXMLDocument; //  <<< tutaj zmiana !!!!
  NodeMain: IXMLNode;
  XMLNode: IXMLNode;
begin
  XML := TXMLDocument.Create(nil);
  XML.FileName := 'C:\prod.xml';
  XML.Active := TRUE;
  NodeMain := XML.ChildNodes.FindNode('tft');
  if Assigned(NodeMain) then
  begin
    XMLNode := NodeMain.ChildNodes.FindNode('id');
    while XMLNode <> nil do
    begin
      ShowMessage(XMLNode.Text);
      XMLNode := XMLNode.NextSibling;
    end;
  end;
end;
0

Jak ja Ci kurka dziękuję!!!! <browar> <browar> :D

Działa ;P Co było powodem błędu? Widzę, że zmieniłeś TXMLDocument na IXMLDocument. No tak... ;P Z literką te mamy obiekty okna, a tutaj deklarujemy element interfejsu :)
Jeszcze raz 1000-krotne dziękuję ;)

0
diron16 napisał(a):

Z literką te mamy obiekty okna, a tutaj deklarujemy element interfejsu :)

No nie za bardzo… Prefiks T informuje, że to zwykły typ danych (w tym przypadku klasa), a I że interfejs – nie ma mowy o żadnych elementach, a tym bardziej „obiektach okna”. Równie dobrze może być na odwrót:

type
  TXMLDocument = interface
    {..}
  end;

type
  IXMLDocument = class
    {..}
  end;

bo prefiksy są umowne, opcjonalne. Ale w tym przypadku akurat są one poprawne.

0
grzegorz_so napisał(a):

zrób tak:

XML:=TXMLDocument.Create(nil);

tylko że wtedy obiekt nie będzie miał ownera i sam musisz zadbać o jego zwolnienie.

Z dokumentacji wynika że ownerem może być obiekt klasy TComponent. Ty użyłeś self, nie wiadomo jaka klasa kryje się pod self

Tylko, że wtedy można się baaaaardzo nadziać na dziwne błędy. Sam popełniłem coś takiego na produkcji i miałem AV i inne błędy w różnych miejscach. Czasem już nawet podczas wczytywania pliku. Tu jest porada co wtedy zrobić http://edn.embarcadero.com/article/29241 Jak jeszcze nie trafiłem na tego arta jako ownera przekazałem... obiekt Application i zaczęło działać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1