Hi,
I'm trying, trying, trying, but without sucess. x(
Find attached, my test example. It uses DOM and XML Reader.
If someone can see where I'm missing in this project, please show me where the error is.
Thx.

Mailing lists / lazarus / 2011-11
27 messages · 11 people · –
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
Hi,
I'm trying, trying, trying, but without sucess. x(
Find attached, my test example. It uses DOM and XML Reader.
If someone can see where I'm missing in this project, please show me where the error is.
Thx.
Oops,
2011/11/27 silvioprog :
If someone can see where I'm missing in this project, please show me where the error is.
If someone see what is wrong, let me know.
I'm trying, trying, trying, but without sucess. x( Find attached, my test example. It…
Anyone? D:
2011/11/27 silvioprog :
I'm trying, trying, trying, but without sucess. x( Find attached, my test example. It…
F*cken hell, now I know why I don't EVER use or work with XML! I had a look at your code, and the problem is seemingly easy, but the solution is definitely not. I tried DocumentElement, .GetElementsByName(), FindNode(), FirstChild() etc... Not a single one returns what I would have expected - most functions simply returned nil. TDOMNode.FindNode() doesn't even have an implementation.
I then thought I would look at Lazarus's TXMLConfig - because surely that uses the DOM to find values. To my surprise, that component implements it's own recursive iteration over nodes to find something - and it's not easy on the eyes. So what the hell is the point of the DOM or TXMLDocument implementation if none of the default implementation can do any searching.
Sorry I tried. I'll leave XML to the really clever people (or rather the insane people for wanting to use XML). I'll stick to INI (or maybe even JSON) files thank you very much. :)
And to be clear, as a programmer, this is the API interface I would expect to use... which I don't think is unreasonable. Obviously this doesn't work, but hey, that's XML for you.
ReadXMLFile(VXML, ExtractFilePath(ParamStr(0)) + 'LazSolutionsDT.lpk');
n := vxml.FindNode('/Config/Package/Version');
n.Attributes.GetNamedItem('Major');
n.Attributes.GetNamedItem('Minor');BTW:
I doubt you can simply search for 'Version', because that node name appears in a few location in the XML hierarchy. So you would somehow need to tell it you are looking for '/Config/Package/Version'.
PS:
I'm very curious to know what the actual solution is though.
uses laz2_xmlcfg
cfg:=TXMLConfig.Create('/path/to/package.lpk');
writeln(cfg.GetValue('Package/Version/Major',''));
writeln(cfg.GetValue('Package/Version/Minor',''));
writeln(cfg.GetValue('Package/Version/Release',''));
writeln(cfg.GetValue('Package/Version/Build',''));
cfg.Free;Mattias
Thanks Mattias, I trust that solves Silvio's problem. Any idea how you do the same with the TXMLDocument class or the DOM unit? Seeing that not all developers would want to use TXMLConfig just to manipulate or search their XML data.
F*cken hell, now I know why I don't EVER use or work with XML! I had a look at your…
Right, using XML without documentation sucks :-(
I had the same impression when I tried to implement XML output of fpdoc projects right now.
I'm not sure why the XML implementation is cluttered into an stack of derived classes, when only TDomElement is halfways usable.
Problem is: typical XML files (see the fpdoc files) have entries of the same name, which has to be interpreted as a node *class* name. The individual node names reside in some arbitrary attribute, maybe 'name', maybe 'key' or something else. That makes a general Find method near impossible :-(
DoDi
Hans-Peter Diettrich wroteRight, using XML without documentation sucks :-(
In this case, I don't think even documentation would have helped.
I had the same impression when I tried to implement XML output of fpdoc projects right now.
I feel your pain. :-)
I'm not sure why the XML implementation is cluttered into an stack of derived classes, when only TDomElement is halfways usable.
As far as I can see, XML handling should be rather simple. After all, it is a classic case of a tree hierarchy of data elements. Two classes only. TXMDocument and TXMLNode. That should be all that is needed to find anything in XML. TXMLNode represents itself, and acts as a container for its child nodes. A basic Composite Design pattern example.
maybe 'key' or something else. That makes a general Find method near impossible :-(
I disagree. Just read the following article I found. This guy use the same idea I mentioned in my example, and as I mentioned above - about composite design pattern.
http://www.delphi3000.com/articles/article_3314.asp?SK=
For those too lazy to read the article, here is the gist of it.
type
TxmlNode = class
property Name: string;
property Value: string;
property Parent: TxmlNode;
property Child[Idx: integer]: TxmlNode;
property ChildrenCount: integer;
property Node[Path:string]: TxmlNode; default;
end;A simple easy to understand API. Node[] takes a Path not a Name. So you can do things like
MyNode.Node[/Config/Package/Version];...and if you need to retrieve a list of nodes...
n := MyNode.Node[/Config/Package/Files];
if Assigned(n) then
begin
for i := 0 to n.ChildrenCount-1 do
begin
....I would even add a FindNode() method which internally uses Node[] - just to make in very clear to the developer using this class.
I guess if I ever need to work with XML (lets hope that never happens), I'll implement my (yet again) own classes. Programming is supposed to solve problems, not create more. The alternative would have been to modify the FCL DOM code, but that would probably cause breakages all over existing code (eg: fpdoc, makeskel etc) - so FCL DOM code is now stuck in near unusable limbo land. :-(
Right, using XML without documentation sucks :-( I had the same impression when I tried…
Hans-Peter Diettrich wroteRight, using XML without documentation sucks :-(
There is some documentation:
http://wiki.lazarus.freepascal.org/XML_Tutorial
In this case, I don't think even documentation would have helped. I feel your pain. :-)…
AFAIK FPC's XML implementation tries to follow the DOM specification of W3C as much as possible. For the specification see here: http://www.w3.org/DOM/DOMTR
Regards,
Sven
In this case, I don't think even documentation would have helped. I feel your pain. :-)…
Graeme, please stop bashing code you personally don't understand.
The code works as designed. It is an implementation of a W3 spec. It passes the W3 test suites, so it is correct code. I use it in many many projects, and it performs flawlessly.
The fact that we follow the W3 spec allows people to easily switch between a Delphi or even a Java DOM implementation and a FPC DOM implementation.
If you think the spec sucks, please complain with the W3 consortium.
It's not because you don't agree with this interface that the "FCL DOM code is now stuck in near unusable limbo land."
I use tiOPF. I do not agree with many decisions that were taken for it's implementation, but I do refrain from bashing tiOPF and saying things like 'tiOPF code is stuck in near unusable limbo land'.
Michael.
<michael.vancanneyt at ...> wroteGraeme, please stop bashing code you personally don't understand.
I guess I deserved that. As for your comment about you never bashing other peoples code.... What about you bashing EpikTimer every time it was mentioned of the last 2+ years. Anyway, lets call it even and move on.
The code works as designed. It is an implementation of a W3 spec. It passes the W3 test suites, so it is correct code. I use it in many many projects, and it performs flawlessly.
OK, so in the spirit of education (for myself and others), and with your fast knowledge of the FPC DOM.... Could you please solve the original problem of Silvio using the FPC DOM (not the TXMLConfig like Mattias did).
29.11.2011 13:17, ?????: I couldn't have said it better. To add to this, the core DOM is…
Sergei Gorelkin wroteTo add to this, the core DOM is simply not supposed to do things like path navigation.
OK, then lets simplify the problem and remove the usage of a "node path". Can you solve to original problem using FPC DOM, but doing it one node retrieval at a time. eg:
xmdoc := TXMLDoc.loadfromfile('the package.lpk')'
configenode := xmldoc.<something here>'
packagenode := confignode.<something here>
versionnode := packagenode.<something here>
major_value := versionnode.<something here>If the FPC DOM is so per W3C spec, surely the W3C spec covers retrieve of simple node somewhere in the XML file? I would just like to know how - so I can LEARN something today.
I guess I deserved that. As for your comment about you never bashing other peoples…
program test;
{$mode objfpc}{$H+}uses
Classes,
SysUtils,
DOM,
XMLRead;var
VXML: TXMLDocument;
N : TDOMNode;
E : TDomELement;
begin
try
ReadXMLFile(VXML, ExtractFilePath(ParamStr(0)) + 'LazSolutionsDT.lpk');
E:=Nil;
// Take first node at 2 levels deep.
N:=VXML.DocumentElement.FirstChild.FirstChild;
While (NNil) and (E=Nil) do
begin
// is it the node we want ?
If (N is TDomElement) and (N.NodeName='Version') then
E:=N as TDomElement;
// Go to next node at the same level.
N:=N.NextSibling;
end;
if Assigned(E) then
// Attributes available as default property of TDomElement.
Writeln('Version ',E['Minor'],' ',E['Release']);
finally
VXML.Free;
end;
end.Michael.
Graeme, please stop bashing code you personally don't understand. The code works as…
29.11.2011 13:17, ?????:
I couldn't have said it better.
To add to this, the core DOM is simply not supposed to do things like path navigation. These tasks are supposed to be done by other modules, like 'traversal' and 'range'. They are powerful, but unfortunately not implemented in FCL. The only more-or-less implemented module is XPath.
Regards,
Sergei
program test; {$mode objfpc}{$H+} uses XMLRead; var VXML: TXMLDocument; N : TDOMNode; E :…
program test; ...snip...
Thanks Michael.
G.
On Tue, Nov 29, 2011 at 9:23 AM, Hans-Peter Diettrich There is some documentation:…
And this documentation is good enough to got me up and running in less than 10 minutes. XML is no black magic and FPCs DOM implmenentation is good enough for most tasks. Switching from QT or Java DOM implementations (which I both used before) to the FPC one was a very smooth and easy transition.
R.
Thanks Michael. G. - Graeme - _______________________________________________ fpGUI - a…
No sweat... DOM is really easy, once you know how it works. But then, isn't everything... ;-)
Michael.
On Tue, Nov 29, 2011 at 9:23 AM, Hans-Peter Diettrich There is some documentation:…
Unfortunately this tutorial doesn't cover the case of updating an XML document with look-alike entries, e.g.
<description file="rtl.xml"/>
<description file="system.xml"/>
It took me much time to figure out, how duplicate entries (of the same file attribute) can be avoided. A documentation of the classes and methods (in fpdoc format) had helped me a lot.
Thanks anyway :-)
DoDi
F*cken hell, now I know why I don't EVER use or work with XML! I had a look at your…
Have a look at the "relinkhtml" program in the fpcdoc repository :-)
OK, then lets simplify the problem and remove the usage of a "node path". Can you solve…
29.11.2011 13:42, Graeme Geldenhuys ?????:
Core DOM includes the following navigation features:
1) Iterating forward: FirstChild, NextSibling properties. Requires a hand-written loop:
var n: TDOMNode;
begin
n:=node.FirstChild;
while assigned(n) do
begin
doSomething(n);
n:=n.NextSibling;
end;
end;2) Iterating backwards: the same as above, but using LastChild and PreviousSibling properties.
3) Getting all *immediate* children of a node as a "list".
var
list: TDOMNodeList;
begin
list:=node.ChildNodes;
for i:=0 to list.count-1 do
doSomething(list[i]);
end;4) Getting *recursive* list of all elements with given name: GetElementsByTagName('foo'); this is not a method of generic TDOMNode, but of TDOMElement and TDOMDocument classes (only these classes can contain child elements).
An important thing to note is that attributes are *not* the part of node tree and can not be navigated using the above methods. To work with attributes, you first have to locate the element to which the attributes belong, then get the attribute node using Element.Attributes[i] property, or Element.GetAttributeNode('foo'), or get directly the attribute value as Element['foo'];
Michael has already posted a good example. However, the original Silvio's code can be made working with minimal modifications, as follows:
var
VXML: TXMLDocument;
el: TDOMElement;
begin
try
ReadXMLFile(VXML, ExtractFilePath(ParamStr(0)) + 'LazSolutionsDT.lpk');
el:=TDOMElement(vxml.GetElementsByTagName('Version').Item[1]);
writeln(el['Minor'],'.',el['Release']);
finally
VXML.Free;
end;
end.Michael's example is more robust and efficient, because it does not depend on actual position of 'Version' element, and it stops as soon as it finds the required element (while this example collects all 'Version' elements in document). This example is of course shorter.
Regards,
Sergei
No sweat... DOM is really easy, once you know how it works. But then, isn't everything...…
Michael Van Canneyt wroteNo sweat... DOM is really easy, once you know how it works.
I'm learning. :)
There are couple of pitfalls obviously, as noted by this post to the fpc-pascal mailing list.
http:/msg04796.html
I'm not sure if the difference between Delphi and FPC still exist.
The other tricky thing was the "hidden text node", and the leaf node that has an "invisible" NodeValue property, but no way of writing that value out to a XML file.
eg:
{ The FPC DOM way... }
n := doc.DocumentElement.FirstChild.FirstChild.NodeName;
v := doc.DocumentElement.FirstChild.FirstChild.FirstChild.NodeValue;
writeln(Format('n = %s v = %s', [n, v]));
{ The FPC DOM way... }
n := doc.DocumentElement.FirstChild.FirstChild.NodeName;
v := doc.DocumentElement.FirstChild.FirstChild.TextContent;
writeln(Format('n = %s v = %s', [n, v]));I got this now. Both the above examples produce the same output. But where in the XML is the following stored?
n := doc.DocumentElement.FirstChild.FirstChild.NodeValue;This always returns a empty string.
I'm using the following XML sample
---------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<BAIS_XML Version='1.0'>
<RESPOND ID="BAIS">
<RESPOND_TIME>2005.01.20 12:26:58</RESPOND_TIME>
</RESPOND>
<REQUEST ID="SI1">
<REQUEST_TIME>2005.01.20 12:26:58</REQUEST_TIME>
</REQUEST>
<CONTENT ID="L1">
<USER ID="simba">
<GROUP ID="1">Operator bank</GROUP>
<NAME>Bisma Jayadi</NAME>
<ALIAS>simba</ALIAS>
<PASSPORT>FB0woDvKVE4AFQW29a9E</PASSPORT>
</USER>
<LOCATION ID="1">
<CODE>UPPTI.1</CODE>
<NAME>Komputer Bisma</NAME>
</LOCATION>
</CONTENT>
</BAIS_XML>
---------------------------------------
PS:
I also had to Google the meaning or difference between a XML Node and an XML Element. I hate XML! :)
Sorry, my mistake. That is just a "summary" of the TXMLNode interface. Here is the full interface from that article's source code. I added the last two properties myself. Note, that this interface has access to attributes.
TxmlNode = class
private
FName: string;
FValue: string;
FParent: TxmlNode;
Attr: TStringList;
Nodes: TList;
FXMLRCTrans: IXMLReservedCharsTranslator;
function GetAttribute(AttrName: string): string;
function GetChild(Idx: integer): TxmlNode;
function GetNode(Path: string): TxmlNode;
procedure SetAttribute(AttrName: string; const Value: string);
procedure SetName(const Value: string);
procedure SetValue(const Value: string);
function GetAttributesCount: integer;
function GetChildrenCount: integer;
function GetAttributeByIdx(Idx: integer): string;
function GetAttributeNameByIdx(Idx: integer): string;
public
constructor Create;
constructor CustomCreate(pName: String);
destructor Destroy; override;
property Name: string read FName write SetName;
property Value: string read FValue write SetValue;
property Parent: TxmlNode read FParent;
property Attribute[AttrName:string]:string read GetAttribute
write SetAttribute;
property AttributeByIdx[Idx: integer]:string read GetAttributeByIdx;
property AttributeNameByIdx[Idx: integer]:string read
GetAttributeNameByIdx;
property AttributesCount: integer read GetAttributesCount;
property Child[Idx: integer]: TxmlNode read GetChild;
property ChildrenCount: integer read GetChildrenCount;
property Node[Path:string]: TxmlNode read GetNode; default;
procedure AddChild(ANode: TxmlNode); overload;
function AddChild(pName, pValue: String): TxmlNode; overload;
function ChildByName(AName: string): TxmlNode;
function AsXml: string;
procedure AsXmlStringList(var pList: TStringList; var pSpacer: Integer);
end;Unfortunately this tutorial doesn't cover the case of updating an XML document with…
And if you document how to do that in the wiki the next person which comes and needs that won't have to figure it out by herself too ;)
Felipe Monteiro de Carvalho wroteAnd if you document how to do that in the wiki the next person which comes and needs that won't have to figure it out by herself too ;)
Better yet, start the dom.pp unit documentation. The sooner it is done, the sooner it will appear in the official FPC documentation. This is one unit that will benefit from many code examples too.
I'm trying, trying, trying, but without sucess. x( Find attached, my test example. It…
Hellow guys!
Sorry for my delay, and sorry if the topic caused some noise.
I solved my problem with the examples shown to me. My project, which does not use the LCL, it worked p.e.r.f.e.c.t.l.y well! :)
Thank you all, now I definitely learned how to use XML with Free Pascal!!! :}D