Adding a node to an existing XML file using inno setup - vb.net

In my inno setup script there is a [code] section and I need to add some code to:
Open an xml file
then add a single node in a specific place
Save the file back to the hard drive
I need to be able to edit a file called config.xml in \documents\docotype
in the file there is some code like this:
<References>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>System.dll</string>
<string>System.Core.dll</string>
<string>System.Drawing.dll</string>
<string>System.Windows.Forms.dll</string>
<string>System.XML.dll</string>
</ArrayOfString>
</References>
I need it to look like this:
<References>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>System.dll</string>
<string>System.Core.dll</string>
<string>System.Drawing.dll</string>
<string>System.Windows.Forms.dll</string>
<string>System.XML.dll</string>
<string>C:\\bin\Custom\cutty109.dll</string>
</ArrayOfString>
</References>
So really I just need to add the following line into the file in the 'ArrayOfString' section
<string>C:\\bin\Custom\cutty109.dll</string>
I'm sure this must be possible but I have no clue how..
Thanks

Please refer the CodeAutomation.iss example provided along with inno install. And use this code instead the original code under the 'Modify the XML document' section.
{ Modify the XML document }
NewNode := XMLDoc.createElement('string');
XMLDoc.setProperty('SelectionLanguage', 'XPath');
RootNode := XMLDoc.selectSingleNode('//References/ArrayOfString');
RootNode.appendChild (NewNode);
RootNode.lastChild.text :='C:\\bin\Custom\cutty109.dll';
{ Save the XML document }

I assume you really need some dynamic way to add to this config file, if not then of course overriding the old one is the simplest method.
To dynamically add sections to a config file, you have some options:
You can create your own command line utility (exe or script) that does the file manipulation and call that utility in the [Run] section of your install script. This could look something like this:
In the [Files] section, you'll have one line for your utility:
Source: "myUtil.exe"; DestDir: "{app}"
In the [Run] section, you'll have one line for each manipulation you need to do in your config, like this:
FileName: "{app}\myUtil.exe"; Parameters: "/addSection:"
OR
You can use Pascal scripting to manipulate your config file. You can create a Pascal that uses CreateOleObject to call msxml.dll for XML the file manipulation. Then, in your [Files] section you can use AfterInstall to to call your Pascal function, like this:
Source: "myFileThatNeedsConfigManipulation.dll"; DestDir: ... ;
AfterInstall: MyPascalFunctionThatDoesTheManipulation

Try something like this:
Dim sXPath : sXPath = "/configuration/References/ArrayOfString"
Dim sAdd : sAdd = "C:\\bin\Custom\cutty109.dll"
Dim sElm : sElm = "string"
Dim sFSpec : sFSpec = resolvePath( "..\data\config.xml" )
Dim oXDoc : Set oXDoc = CreateObject( "Msxml2.DOMDocument" )
oXDoc.setProperty "SelectionLanguage", "XPath"
oXDoc.async = False
oXDoc.load sFSpec
If 0 = oXDoc.ParseError Then
WScript.Echo sFSpec, "looks ok"
Dim ndFnd : Set ndFnd = oXDoc.selectSingleNode( sXPath )
If ndFnd Is Nothing Then
WScript.Echo "|", sXPath, "| not found"
Else
WScript.Echo "found |" & ndFnd.tagName & "|"
Dim ndNew : Set ndNew = oXDoc.createElement( sElm )
ndNew.appendChild oXDoc.createTextNode( sAdd )
ndFnd.appendChild ndNew
WScript.Echo "After appending:"
WScript.Echo oXDoc.xml
oXDoc.Save Replace( sFSpec, ".xml", "-2.xml" )
End If
Else
WScript.Echo oXDoc.ParseError.Reason
End If
The steps:
create a Msxml2.DOMDocument
use XPath to find the node to change
create a now string element and append the text
append the new node to the found node
save the modified XML

Related

VTD-XML creating an XML document

I am a bit confused on how to do this, all of the docs / examples show how to read and edit xml docs but there doesn't seem to be any clear way of creating an xml from scratch, I would rather not have to ship my program with a dummy xml file in order to edit one. any ideas? thanks.
What you could do instead would be to just hard-code an empty document like this:
byte[] emptyDoc = "<?xml version='1.0' encoding='UTF-8'?><root></root>".getBytes("UTF-8");
And then use that to create your VTDGen and XMLModifier, and start adding elements:
VTDGen vg = new VTDGen();
vg.setDoc(emptyDoc);
vg.parse(true);
VTDNav vn = vg.getNav();
XMLModifier xm = new XMLModifier(vn);
// Cursor is at root, update Root Element Name
xm.updateElementName("employee");
xm.insertAttribute(" id='6'");
xm.insertAfterHead("<name>Bob Smith</name>");
vn = xm.outputAndReparse();
// etc...

OpenERP custom report filename

I would like to customize reports filename.
For instance, when I download an invoice, I will have something like 'Invoice.pdf' as filename. What I would like is something like 'invoice_number.pdf' but I don't know how to use dynamic file name ?
I found a way for 7.0 and current trunk:
For a quick fix, take a look at the Reports class in:
openerp-7.0\web\addons\web\controllers\main.py
The report name is set in a variable named file_name:
file_name = '%s.%s' % (file_name, report_struct['format'])
Find this line and insert this part before it:
'''
YP: Added proc. to create reports with real object names (the object must have a field named "name"):
eg: "PO00006.pdf" instead of "Request For Quotation.pdf" for a single object report
"PO00006-PO00002.pdf" instead of "Request For Quotation.pdf" for a multiple objects report
'''
# Try to get current object model and their ids from context
if action.has_key('context'):
action_context = action.get('context',{})
if action_context.has_key('active_model') and action_context.has_key('active_id'):
action_active_model = action_context.get('active_model','')
action_active_ids = action_context.get('active_ids', [])
if action_active_model and action_active_ids:
# Use built-in ORM method to get data from DB
m = req.session.model(action_active_model)
r = m.read(action_active_ids, False, context)
# Parse result to create a better filename
for i, item in enumerate(r):
if item.has_key('name'):
if i == 0:
file_name = ('%s') % (item['name'])
else:
file_name = ('%s-%s') % (file_name, item['name'])
For a quick fix, take a look at the Reports class in:
openerp-6.1\web\addons\web\controllers\main.py
The report name is set in a variable named header.
For my needs, I only want the report to be named by the object name (that's suitable in 99% of cases) so I added a new variable named report_name:
report_name = action['report_name']
if action.has_key('context'):
action_context = action.get('context',{})
if action_context.has_key('name'):
report_name = action_context['name']
return req.make_response(report,
headers=[
('Content-Disposition', 'attachment; filename="%s.%s"' % (report_name, report_struct['format'])),
('Content-Type', report_mimetype),
('Content-Length', len(report))],
cookies={'fileToken': int(token)})
I found a solution to set the default filename like the attach file name, using the expression in the attachment attribute in your xml report definition.
Found and modify this file: openerp7/openerp-web/addons/web/controllers/main.py.
Search this sentence:
file_name = '%s.%s' % (file_name, report_struct['format'])
Then add this code before:
'''Code added by Raul Paz to set the default file_name like the attach_name
The attach_name mach with the attachment expresion from your report_xml
<report
id="report_webkit.YourModule_report_id"
model="YourModule.model"
name="Your_report_name"
file="YOUR_MODULE/report/YOUR_MAKO_FILE.mako"
string="Your Text in the print button"
auto="False"
report_type="webkit"
attachment="'Valid_filename_expresion"
usage="default"
/>
And
to modify existing report sale_report.xml to manage the name:
create in your module a file : sale_report.xml
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="sale.report_sale_order" model="ir.actions.report.xml">
<field name="attachment">(object.name or 'Sale Order')</field>
<field name="attachment_use" eval="True"/>
</record>
</data>
</openerp>
'''
try:
if action.get('attachment_use',False) and action['attachment']:
model = context['active_model']
cr = openerp.pooler.get_db(req.session._db).cursor()
uid = context['uid']
ids = context['active_ids']
objects=openerp.pooler.get_pool(req.session._db).get(model).browse(cr,uid,ids,context=context)
file_name=[eval(action['attachment'],{'object':x, 'time':time}) for x in objects][0]
except:
pass
#end code added
Good luky

parsing tcx document using xdocument selectsinglenode

I am trying to parse an TCX document similiar to the one used in this post: Import TCX into R using XML package
Only I'm trying to use XmlDocument.SelectNodes and SelectSingleNode instead of getNodeSet. The line with xmlns looks like this:
<TrainingCenterDatabase xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd">
If I remove the xmlns and just have , I can parse it without any problems.
My (vb.net) code:
Dim tcxXmlDocument As New System.Xml.XmlDocument()
tcxXmlDocument.Load(tcxFile)
Dim xmlnsManager = New System.Xml.XmlNamespaceManager(tcxXmlDocument.NameTable)
Dim trackpoints As New List(Of Trackpoint)
For Each tpXml As System.Xml.XmlNode In tcxXmlDocument.SelectNodes("//Trackpoint", xmlnsManager)
Dim newTrackpoint As New Trackpoint
With newTrackpoint
.Time = tpXml.SelectSingleNode("Time").InnerText
.LatitudeDegrees = tpXml.SelectSingleNode("Position/LatitudeDegrees").InnerText
.LongitudeDegrees = tpXml.SelectSingleNode("Position/LongitudeDegrees").InnerText
.HeartRateBpm = tpXml.SelectSingleNode("HeartRateBpm").InnerText
End With
trackpoints.Add(newTrackpoint)
Next
How can I configure the XmlNamespaceManager so that I can access the nodes in such a tcx document?
Thanks,
Jason
Use the XmlNamespaceManager.AddNamespace() method to associate a preffix (say "x") with the namespace "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2".
Then in your XPath expression, pefix every element name with the "x" prefix.
Replace this:
//Trackpoint
with:
//x:Trackpoint
Replace this:
Time
with:
x:Time
Replace this:
Position/LatitudeDegrees
with:
x:Position/x:LatitudeDegrees
Replace this:
Position/LongitudeDegrees
with:
x:Position/x:LongitudeDegrees
Finally, replace this:
HeartRateBpm
with:
x:HeartRateBpm

vb.Net: How can I read a large XML file quickly?

I am trying to read this XML document.
An excerpt:
<datafile xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="wiitdb.xsd">
<WiiTDB version="20100217113738" games="2368"/>
<game name="Help Wanted: 50 Wacky Jobs (DEMO) (USA) (EN)">
<id>DHKE18</id>
<type/>
<region>NTSC-U</region>
<languages>EN</languages>
<locale lang="EN">
<title>Help Wanted: 50 Wacky Jobs (DEMO)</title>
<synopsis/>
</locale>
<developer>HUDSON SOFT CO., LTD.</developer>
<publisher>Hudson Entertainment, Inc.</publisher>
<date year="2009" month="" day=""/>
<genre>party</genre>
<rating type="ESRB" value="E10+">
<descriptor>comic mischief</descriptor>
<descriptor>mild cartoon violence</descriptor>
<descriptor>mild suggestive themes</descriptor>
</rating>
<wi-fi players="0"/>
<input players="2">
<control type="wiimote" required="true"/>
<control type="nunchuk" required="true"/>
</input>
<rom version="" name="Help Wanted: 50 Wacky Jobs (DEMO) (USA) (EN).iso" size="4699979776"/>
</game>
So far I have this:
Dim doc as XPathDocument
Dim nav as XPathNavigator
Dim iter as XPathNodeIterator
Dim lstNav As XPathNavigator
Dim iterNews As XPathNodeIterator
doc = New XPathDocument("wiitdb.xml")
nav = doc.CreateNavigator
iter = nav.Select("/WiiTDB/game") 'Your node name goes here
'Loop through the records in that node
While iter.MoveNext
'Get the data we need from the node
lstNav = iter.Current
iterNews = lstNav.SelectDescendants(XPathNodeType.Element, False)
'Loop through the child nodes
txtOutput.Text = txtOutput.Text & vbNewLine & iterNews.Current.Name & ": " & iterNews.Current.Value
End While
It just skips the "While iter.MoveNext" part of the code. I tries it with a simple XML file, and it works fine.
I think your XPath query is off. WiiTDB is a closed node, so you need to look for /datafile/game or //game.
Use the System.Xml.Serialization namespace instead: create a dedicated, serializable class to hold the data you wish to load and define shared serialize / deserialize functions with strongly typed arguments to do the work for you.
As the structure of the new classes will closely follow that of your XML data, there should be no confusion as to which data is located where within a run time instance.
See my answer here for an idea of how to create a class from an example XML file.

ClearCase : list the content of a directory (ls) using CAL

In ClearCase, you can list the content of a directory using "cleartool ls".
My question is how can I do the same thing using CAL (ClearCase Automation Layer). The reason I prefer the COM API is because I won't have to parse the output of "ls".
So far, I am able to get the VOB and the View successfully, but I didn't find any method for listing the content.
My code so far:
IClearCase cc = new ApplicationClass();
CCVOB vob = cc.get_VOB("\\VOB-name");
CCView view = cc.get_View("ViewTag");
Thank you for your help.
I wrote VonC's answer in C# for those interrested.
string[] files = Directory.GetFiles("View path here", "*.*", SearchOption.AllDirectories);
foreach (string file in files)
{
try
{
CCVersion ver = cc.get_Version(file);
Console.WriteLine(ver.Path);
}
catch(Exception) {/*the file is not versioned*/}
}
May be this is a good start:
Set CC = Wscript.CreateObject("ClearCase.Application")
Set DirVer = CC.Version(".")
Set FSO = CreateObject("Scripting.FileSystemObject")
Set Folder = FSO.GetFolder(DirVer.Path)
Wscript.Echo "Files under source control: "
For Each File in Folder.Files
On Error Resume Next
Set Ver = CC.Version(File.Name)
If Err.Number = 0 Then
Wscript.Echo Ver.ExtendedPath
End If
Next
The idea being to use ICCVersion methods to try accessing the version of a file. If it does not return an error, it is indeed a versioned file.
Now I know the file is versioned, how can I remove it (rmname).
Do not use RemoveVersion():
Removes irretrievably the version (equivalent to cleartool rmver)
WARNING! This is a potentially destructive operation. Because CAL does not prompt the user for input under any circumstances, there is no confirmation step when RemoveVersion is invoked. Invoking RemoveVersion is equivalent to running cleartool rmver with the -force option.
Instead use the RemoveName from the ICCElement interface.