Skip to content
⌘ NSIS Forum Archive

XML plugin

118 posts

Instructor#

XML plugin

XML plugin parses an XML document, and builds from that a Document Object Model (DOM) that can be read, modified and saved. XML plugin is based on TinyXml (2.4.0 RC).

Features:
- Read and/or modified xml files
- Code is fast and lightweight
- Unicode UTF-8 support
- "MSXML.DLL" independent
- Support for condense and non-condense white spaces
- Row and Column tracking


"XML" plugin v1.0 (See the Wiki for v2 or further down in this thread for v1.7)
Instructor#
Changes:
- TinyXml updated to v2.4.1
- Fixed: output variable in xml::NoChildren
- New: xml::GetText
   Convenience function for easy access to the text inside current element.
- New: xml::SetCDATA
   Turns on or off a CDATA representation of the current element text.
- New: xml::IsCDATA
   Queries whether this represents text using a CDATA section.


"XML" plugin v1.1
Comm@nder21#
next plugin i repack for correct usage of nsis file structure 🙂
Instructor#
-TinyXml updated to v2.4.2
-Fixed: "CreateNode" appearance of the "\r\n" at the end (thanks Lee Thomason)
-Fixed: Now error appears if current node is TEXT and uses "InsertEndChild"
-Changed: "AttributeByName" -> "GetAttribute" now not only returns value of the attribute, but also goes to it
-New: "GetNodeValue" can be useful in some cases


"XML" plugin v1.2
false#
How would I go about selecting a particular node by it's name? Like how Olivier Marcoux's NSIS XML uses...

nsisXML::select <XPath expression>

Thx!
Instructor#
If you want to "select" the node you need go to it (FirstChildElement, NextSiblingElement ...). Easy for me, when you ask the concrete example, what you trying to do.
false#
Somewhere nested in my XML, I have a set of child nodes who have the same name and share the same parent. The child nodes differ by having different attributes values.

I would like to test if a particular node exists in an XML without having to drill down using FirstChildElement and NextSiblingElement. If the node with the target node name exists, I would make it the current node.

I thought GotoHandle would do this for me but I am wrong in thinking it takes in a node name for a parameter.
Instructor#edited
New: [xml::FindNextElement /NOUNLOAD "[name]" .r0 .r1]
&nbsp;&nbsp;&nbsp;-Search for element (recursive), returns the element name and goes to it.
New: [xml::FindCloseElement /NOUNLOAD]
&nbsp;&nbsp;&nbsp;-Closes search opened by xml::FindNextElement.
New: [xml::ElementPath /NOUNLOAD .r0]
&nbsp;&nbsp;&nbsp;-Returns the current element path.
&nbsp;&nbsp;&nbsp;(e.g. "/a/b/c[3]/d")
New: [xml::GotoPath /NOUNLOAD "[path]" .r0]
&nbsp;&nbsp;&nbsp;-Goes to the specified path.
&nbsp;&nbsp;&nbsp;(e.g. from root "/a/b[2]/c/d", from current element "a/b[2]/c/d",
&nbsp;&nbsp;&nbsp;&nbsp;using last element 'b' "a/b[-1]/c/d")


"XML" plugin v1.3
Instructor#
DOM builds by TinyXML parser, so UTF-16 is depend on this project. BTW: Where is already have feature request about it.
Instructor#
Added: now "GotoPath" can accept elements without name (e.g. using any last element "a/[-1]/c/d")


"XML" plugin v1.4
Instructor#
Fixed: Now "ElementPath" and "GotoPath" correctly working with the document beginning. If "ElementPath" returns "" - the current element is the beginning of the document. [xml::GotoPath /NOUNLOAD "" .r0] - go to the document beginning.


"XML" plugin v1.5
Guest#
Bug in GetAttribute

Hi,

there seems to be a bug in the GetAttribute Method, it returns
always -1 for the first attribute of a node.

A possible workaround is to check if the FirstAttribute differs from the desired attribute.

Kind Regards,

Rob
chagam#
Hi,

May be I'm missing something but I don't understand how to replace a text value.

There's a xml::GetText function. How do I do a xml::SetText ?

Thanks in advance

Chag
Guest#
Originally posted by chagam
Hi,

May be I'm missing something but I don't understand how to replace a text value.

There's a xml::GetText function. How do I do a xml::SetText ?

Thanks in advance

Chag
Did you try the xml::SetNodeValue method ?
chagam#
Hi,

Yes, I tried. May be a did something wrong.

My xml file looks like this :
<config>
<local>
<host>test</host>
</local>
</config>

I tried :
xml::GotoPath /NOUNLOAD "/config/local/host" .r0
xml::SetNodeValue /NOUNLOAD "1234" .r0

and my new xml file looks like this :
<config>
<local>1234
</local>
</config>

Chag
Instructor#
Name "XMLTest"
OutFile "XMLTest.exe"

Section
xml::LoadFile /NOUNLOAD "test.xml" .r0
MessageBox MB_OK "xml::LoadFile$\n$$0=$0"

xml::GotoPath /NOUNLOAD "/config/local/host" .r0
MessageBox MB_OK "xml::GotoPath$\n$$0=$0"

xml::FirstChild /NOUNLOAD "" .r0 .r1
MessageBox MB_OK "xml::FirstChild$\n$$0=$0$\n$$1=$1"

xml::SetNodeValue /NOUNLOAD "1234"
MessageBox MB_OK "xml::SetNodeValue"

xml::SaveFile "test_saved.xml" .r0
MessageBox MB_OK "xml::SaveFile$\n$$0=$0"
SectionEnd
Instructor#edited
there seems to be a bug in the GetAttribute Method, it returns
always -1 for the first attribute of a node.
Fixed, thanks.
Instructor#edited
Fixed: GetAttribute returns -1 for the first attribute.
New: "SetText" -convenience function for easy set the text of the current element.


"XML" plugin v1.6
xilay#
Hello,

I need to create a new element without text.
I use this code :
xml::LoadFile /NOUNLOAD "test.xml" .r0
xml::GotoPath /NOUNLOAD "/root" .r0
xml::CreateNode /NOUNLOAD "<histo></histo>" .r0
xml::InsertEndChild /NOUNLOAD "$0" .r0
xml::SaveFile /NOUNLOAD "test.xml" .r0 
But the new element is with a blank at the end, like this :
<root>
    <histo />
</root> 
If I create the element with text, it's ok.
Have you got an idea?

Thanks

(sorry if my english is not very good)
Comm@nder21#
this is correct xml behaviour.
empty elements have to be <element />, not <element></element>.

last one is no valid xml!
xilay#
Yes, I know, the problem is the blank after 'histo'.
I have this <histo /> (you see, the blank between 'histo' and '/') and not this <histo/>.

Sorry for my bad explanation 🙁
Comperio#
W3.org (which pretty much has the final word on markup languages like XML) recommends that a space should be used when declaring empty tags.

So this would be proper XML:
<histo />

NOT this:
<histo/>

See the section tags for empty elements at http://www.w3.org/TR/REC-xml/#sec-starttags for more info.

[edit]
And FWIW, I've always seen empty tags written using a space between the element name and the '/' character...
xilay#
Ok, I use xmlspy and it deletes the blank, so, I thought it was not normal.
Thanks a lot (and thanks for this perfect plugin)
Instructor#
Updated: TinyXml to v2.4.3
Changed: Now plugin used header "XML.nsh" for custom user variables and
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;better compile errors check.

Update from previous versions:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Insert line in script:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!include "XML.nsh"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Replace:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xml::LoadFile -> ${xml::LoadFile} ...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Replace:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.r0 -> $0, .r1 -> $1 ... .R0 -> $R0, .R1 -> $R1 ...

"XML" plugin v1.7
stwhit#
I need to be able to parse two XML documents at the same time (because I'm merging them during an upgrade process).

From looking at the API and the source code, it looks like this XML plugin only supports working on a single XML document at a time, because there is no concept of a file handle being returned by ${xml::LoadFile} and being passed to the other functions. It looks like there is a single, global XML document being edited (TiXmlDocument doc).

So, two questions:

1. Is it possible to edit two XML documents at the same time using this plugin?
2. If not, would you consider enhancing the plugin to use file handles to support editing multiple XML documents at once?

Thanks!