Recent

Author Topic: [Solved] Modify XML Node Text  (Read 3502 times)

nikel

  • Full Member
  • ***
  • Posts: 186
[Solved] Modify XML Node Text
« on: December 12, 2018, 02:34:40 pm »
Hi, I searched a lot on the net but couldn't find a simple snippet. I have this xml:

Code: XML  [Select][+][-]
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <channel>
  3.   <updates>true</updates>
  4.   <rememberSettings>false</rememberSettings>
  5.   <action></action>
  6.   <file></file>
  7.   <scheduleType></scheduleType>
  8.   <hour></hour>
  9.   <min></min>
  10.   <countDownMin></countDownMin>
  11.   <idleMin></idleMin>
  12. </channel>

How can I insert text between tags?
« Last Edit: December 13, 2018, 09:27:49 am by nikel »

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Modify XML Node Text
« Reply #1 on: December 12, 2018, 02:58:46 pm »
This is an example taken from one of my apps:

Code: Pascal  [Select][+][-]
  1. procedure TConverter.DoAddModDate(Page: TW2XHTMLPage);
  2. var
  3.   Node: TDOMElement;
  4.   doc: TXMLDocument;
  5. begin
  6.   doc:=Page.XHTML;
  7.   { Creates <p></p>}
  8.   Node := doc.CreateElement('p');
  9.   { Adds it to the Page }
  10.   Page.BodyDOMNode.AppendChild(Node);
  11.   { sets attribute: <p class="imdate"> }
  12.   Node.SetAttribute('class', 'lmdate');
  13.  { Adds the text of the paragraph }
  14.   Node.AppendChild(doc.CreateTextNode(
  15.     'Last modified on ' + Page.WikiPage.TimeStamp));
  16. end;
  17.  

You can find more complete examples in the source folders and in the wiki; p.e. the XML Tutorial

ETA My app borrows heavily from wikiconvert, which you can find in your [Lazarus]/components/wiki/ folder. :)
« Last Edit: December 12, 2018, 03:03:13 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

nikel

  • Full Member
  • ***
  • Posts: 186
Re: Modify XML Node Text
« Reply #2 on: December 12, 2018, 03:51:28 pm »
Hi, I just want to change node value. Thanks.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Modify XML Node Text
« Reply #3 on: December 12, 2018, 08:07:33 pm »
Hi, I just want to change node value. Thanks.

Then use the function ReplaceChild() instead of AppendChild() (in line 14). You'll have to add some more code, though to create the new text node before calling ReplaceChild()

It's a pity that fcl-xml is almost completely undocumented (only in the wiki) :(
« Last Edit: December 12, 2018, 08:19:00 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

nikel

  • Full Member
  • ***
  • Posts: 186
Re: Modify XML Node Text
« Reply #4 on: December 12, 2018, 09:58:50 pm »
I tried this:

Code: Pascal  [Select][+][-]
  1. procedure TSettings_Frm.FormClose(Sender: TObject; var CloseAction: TCloseAction
  2.   );
  3. var
  4.   XmlDoc: TXMLDocument;
  5.   itemLineNodeList: TDOMNodeList;
  6.   curNode: TDOMNode;
  7.   i: Integer;
  8. begin
  9.   try
  10.     //ShowMessage('Starting path: ' + GetCurrentDir());
  11.     ReadXMLFile(XmlDoc, 'settings.xml');
  12.  
  13.     itemLineNodeList:= XmlDoc.GetElementsByTagName('updates');
  14.     if not Assigned(itemLineNodeList) then exit;
  15.  
  16.     curNode:= itemLineNodeList[4];
  17.     curNode.NodeValue:=CheckForUpdates_Chbx.Checked.ToString;
  18.     XmlDoc.ReplaceChild(itemLineNodeList[4], curNode);
  19.  
  20.     writeXMLFile(XmlDoc, 'settings.xml');
  21.   finally
  22.     XmlDoc.Free;
  23.   end;
  24. end;

But I'm getting error at runtime for this line:
Code: Pascal  [Select][+][-]
  1. curNode.NodeValue:=CheckForUpdates_Chbx.Checked.ToString;


lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Modify XML Node Text
« Reply #5 on: December 12, 2018, 11:09:53 pm »
I tried this:

Code: Pascal  [Select][+][-]
  1. procedure TSettings_Frm.FormClose(Sender: TObject; var CloseAction: TCloseAction
  2.   );
  3. var
  4.   XmlDoc: TXMLDocument;
  5.   itemLineNodeList: TDOMNodeList;
  6.   curNode: TDOMNode;
  7.   i: Integer;
  8. begin
  9.   try
  10.     //ShowMessage('Starting path: ' + GetCurrentDir());
  11.     ReadXMLFile(XmlDoc, 'settings.xml');
  12.  
  13.     itemLineNodeList:= XmlDoc.GetElementsByTagName('updates');
  14.     if not Assigned(itemLineNodeList) then exit;
  15.  
  16.     curNode:= itemLineNodeList[4];
  17.     curNode.NodeValue:=CheckForUpdates_Chbx.Checked.ToString;
  18.     XmlDoc.ReplaceChild(itemLineNodeList[4], curNode);
  19.  
  20.     writeXMLFile(XmlDoc, 'settings.xml');
  21.   finally
  22.     XmlDoc.Free;
  23.   end;
  24. end;

But I'm getting error at runtime for this line:
Code: Pascal  [Select][+][-]
  1. curNode.NodeValue:=CheckForUpdates_Chbx.Checked.ToString;

Which error are you getting?

Anyway, the node you're getting with curNode:= itemLineNodeList[4] is not yet the text node inside the update; to change the text node you'll have to find the child node of curNode which suppossing your XML is something like:
Code: XML  [Select][+][-]
  1. <update>some string</update>
you could do with
Code: Pascal  [Select][+][-]
  1. curNode.FirstChild
, so try like this:

Code: Pascal  [Select][+][-]
  1. procedure TSettings_Frm.FormClose(Sender: TObject; var CloseAction: TCloseAction
  2.   );
  3. var
  4.   XmlDoc: TXMLDocument;
  5.   itemLineNodeList: TDOMNodeList;
  6.   curNode: TDOMNode;
  7.   i: Integer;
  8. begin
  9.   try
  10.     //ShowMessage('Starting path: ' + GetCurrentDir());
  11.     ReadXMLFile(XmlDoc, 'settings.xml');
  12.  
  13.     itemLineNodeList:= XmlDoc.GetElementsByTagName('updates');
  14.     if not Assigned(itemLineNodeList) then exit;
  15.  
  16.     curNode:= itemLineNodeList[4];
  17.     if curNode.FirstChild.NodeType = TEXT_NODE then begin
  18.       curNode.FirstChild.NodeValue := CheckForUpdates_Chbx.Checked.ToString;
  19.       XmlDoc.ReplaceChild(itemLineNodeList[4], curNode);
  20.     end else
  21.       curNode.AppendChild(XMLDoc.CreateTextNode(
  22.           CheckForUpdates_Chbx.Checked.ToString));
  23.  
  24.     writeXMLFile(XmlDoc, 'settings.xml');
  25.   finally
  26.     XmlDoc.Free;
  27.   end;
  28. end;

Not the best of implementations but it should work (although I have tha nagging suspicion I'm forgetting something important ... :-\ )
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

nikel

  • Full Member
  • ***
  • Posts: 186
Re: Modify XML Node Text
« Reply #6 on: December 13, 2018, 05:34:54 am »
That helped a lot. I changed curNode type to TDOMNodeList and the item number as you stated. Here's my final code:

procedure TSettings_Frm.FormClose(Sender: TObject; var CloseAction: TCloseAction
  );
var
  XmlDoc: TXMLDocument;
  itemLineNodeList: TDOMNodeList;
  curNode: TDOMNodeList;
  i: Integer;
begin
  try
    //ShowMessage('Starting path: ' + GetCurrentDir());
    ReadXMLFile(XmlDoc, 'settings.xml');

    itemLineNodeList:= XmlDoc.GetChildNodes;
    if not Assigned(itemLineNodeList) then exit;

    curNode:= itemLineNodeList;

    curNode[0].NodeValue := CheckForUpdates_Chbx.Checked.ToString;
    XmlDoc.ReplaceChild(itemLineNodeList[0], curNode[0]);

    writeXMLFile(XmlDoc, 'settings.xml');
  finally
    XmlDoc.Free;
  end;
end;

Now it works fine. Thanks again.


I tried this code, yes it writes to xml file but new value isn't saved.

Code: Pascal  [Select][+][-]
  1. procedure TSettings_Frm.FormClose(Sender: TObject; var CloseAction: TCloseAction
  2.   );
  3. var
  4.   XmlDoc: TXMLDocument;
  5.   itemLineNodeList: TDOMNodeList;
  6.   TempNodeList: TDOMNodeList;
  7. begin
  8.   try
  9.     ReadXMLFile(XmlDoc, 'settings.xml');
  10.  
  11.     itemLineNodeList:= XmlDoc.FirstChild.GetChildNodes;
  12.     if not Assigned(itemLineNodeList) then
  13.     begin
  14.       ShowMessage('Not assigned');
  15.       exit;
  16.     end;
  17.  
  18.     TempNodeList:= itemLineNodeList;
  19.  
  20.     TempNodeList[0].NodeValue := CheckForUpdates_Chbx.Checked.ToString;
  21.     ShowMessage(TempNodeList[0].NodeName);
  22.     XmlDoc.FirstChild.ReplaceChild(itemLineNodeList[0], TempNodeList[0]);
  23.  
  24.     writeXMLFile(XmlDoc, 'settings.xml');
  25.   finally
  26.     XmlDoc.Free;
  27.   end;
  28. end;

And how can I assign a nodelist to xmldoc?
« Last Edit: December 13, 2018, 09:13:48 am by nikel »

nikel

  • Full Member
  • ***
  • Posts: 186
Re: Modify XML Node Text
« Reply #7 on: December 13, 2018, 09:27:25 am »
Finally I fixed it. I just changed line in above code:

Code: Pascal  [Select][+][-]
  1. TempNodeList[0].NodeValue :=
to
Code: Pascal  [Select][+][-]
  1. TempNodeList[0].TextContent :=

I want to publish this code Free Pascal wiki. Is that possible?

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: [Solved] Modify XML Node Text
« Reply #8 on: December 13, 2018, 09:49:36 am »
Register to the wiki, log in, and the "Edit" button will be available to you. The wiki has its own markup language. Look at the existing page content or click on the "Help" in the left sidebar to learn it.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Modify XML Node Text
« Reply #9 on: December 13, 2018, 11:41:11 am »
Finally I fixed it. I just changed line in above code:
Code: Pascal  [Select][+][-]
  1. TempNodeList[0].NodeValue :=
to
Code: Pascal  [Select][+][-]
  1. TempNodeList[0].TextContent :=

That's what I was forgetting: TextContent, not NodeValue!!! Yes, that would be a magnific addition to the XML Tutorial of the wiki.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

 

TinyPortal © 2005-2018