How to add data to an element with ActiveState's dom package - dom

In TCL, if you use the DOM package (available in the ActiveState distribution) you can create an xml.
set xmlDoc [::dom::create]
set root [::dom::document createElement $xmlDoc "trafficStatistics"]
set statElement [::dom::document createElement $root "Tx_Frames"]
::dom::element setAttribute $statElement "type" "numericlist"
::dom::element setAttribute $statElement "displayName" "Tx Frames"
puts [::dom::serialize $xmlDoc -indent true]
creating this simple xml:
<result>
<trafficStatistics type="structure">
<Tx_Frames type="numericlist" displayName="Tx Frames"></Tx_Frames>
</trafficStatistics>
</result>
How can I add some data to the Tx_Frames element?
<Tx_Frames type="numericlist" displayName="Tx Frames">some data</Tx_Frames>
Note that the dom package is actually a wrapper over libxml2

I believe you want the ::dom::document createTextNode command. For example:
::dom::document createTextNode $statElement "some data"
When I add this command to your sample script:
set xmlDoc [::dom::create]
set root [::dom::document createElement $xmlDoc "trafficStatistics"]
set statElement [::dom::document createElement $root "Tx_Frames"]
::dom::element setAttribute $statElement "type" "numericlist"
::dom::element setAttribute $statElement "displayName" "Tx Frames"
::dom::document createTextNode $statElement "some data"
It produces this XML:
<trafficStatistics>
<Tx_Frames type="numericlist" displayName="Tx Frames">some data</Tx_Frames>
</trafficStatistics>
You can find documentation for the dom package here:
http://docs.activestate.com/activetcl/8.5/tcldom/index.html
Hope that helps,
Eric Melski

Related

Powershell, modify TXT/XML file to add a string after a specific variable?

Trying to edit the DyanmoSettings.xml file without installing any specific packages on the Windows systems (sed, awk, etc)
to do:
need to modify this file;
%appdata%\dynamo\Dynamo Revit\2.3\DynamoSettings.xml
and within that file above, find this line;
>
> <CustomPackageFolders>
> <string>C:\Users\user1.mydomain\AppData\Roaming\Dynamo\Dynamo Revit\2.3</string>
> </CustomPackageFolders>
>
and add 'C:\Users%USERNAME%\OneDrive\DT-s\Revit Scripts\Dynamo\Custom Packages '
so it looks like this;
>
> <CustomPackageFolders>
> <string>C:\Users\user1.mydomain\AppData\Roaming\Dynamo\Dynamo Revit\2.3</string>
> <string>C:\Users\%USERNAME%\OneDrive\DT-s\Revit Scripts\Dynamo\Custom Packages </string>
> </CustomPackageFolders>
>
>
TIA!
tried using standard >> method in CMD but this didn't work.
Powershell uses c#. So any c# code can run inside powershell without any installation. Code below uses the c# library Xml Linq. Try following
using assembly System
using assembly System.Xml.Linq
$Filename = "c:\temp\test.xml"
$xDoc = [System.Xml.Linq.XDocument]::Load($Filename)
$customFolder = $xDoc.Descendants("CustomPackageFolders")
$newElement = [System.Xml.Linq.XElement]::new("string","C:\Users\%USERNAME%\OneDrive\DT-s\Revit Scripts\Dynamo\Custom Packages")
$customFolder.Add($newElement)
Write-Host "customFolder = " $customFolder
$xDoc.Save("c:\temp\test1.xml")
If that xml file looks anything like this
<DynamOconfig>
<CustomPackageFolders>
<string>C:\Users\user1.mydomain\AppData\Roaming\Dynamo\Dynamo Revit\2.3</string>
</CustomPackageFolders>
</DynamOconfig>
then
# load the settings file
$xml = [System.Xml.XmlDocument]::new()
$xml.Load("$env:APPDATA\dynamo\Dynamo Revit\2.3\DynamoSettings.xml")
# create a new <string> node
$newNode = $xml.CreateElement('string')
$newNode.InnerText = 'C:\Users\%USERNAME%\OneDrive\DT-s\Revit Scripts\Dynamo\Custom Packages'
# find the <CustomPackageFolders> node and append the new node to it
[void]$xml.SelectSingleNode('//CustomPackageFolders').AppendChild($newNode)
# save to (for safety NEW) file
$xml.Save("$env:APPDATA\dynamo\Dynamo Revit\2.3\NEW_DynamoSettings.xml")
Result:
<DynamOconfig>
<CustomPackageFolders>
<string>C:\Users\user1.mydomain\AppData\Roaming\Dynamo\Dynamo Revit\2.3</string>
<string>C:\Users\%USERNAME%\OneDrive\DT-s\Revit Scripts\Dynamo\Custom Packages</string>
</CustomPackageFolders>
</DynamOconfig>
P.S. If your intention is to have %USERNAME% interpolated in the string so it expands to your username, then create the new node's innertext like ths:
$newNode.InnerText = "C:\Users\$env:USERNAME\OneDrive\DT-s\Revit Scripts\Dynamo\Custom Packages"
(mind you need double-quotes now)

Add node CATEGORIES to vcard with perl module "vCard::AddressBook"

I do not find a possibility to add nodes like CATEGORIES or ORG to a vcard object when using the perl module vCard::AddressBook (https://metacpan.org/pod/vCard::AddressBook).
The output should look like this:
BEGIN:VCARD
VERSION:4.0
...
N:Doe;John;;;
...
ORG:Organization_01;
CATEGORIES:Cat_01
...
END:VCARD
When I use the following code:
use vCard::AddressBook;
my $address_book = vCard::AddressBook->new();
my $vcard = $address_book->add_vcard;
$vcard->given_names(['John']);
$vcard->family_names(['Doe']);
$vcard->categories(['Cat_01']); ## DOES NOT WORK
my $file = $address_book->as_file('file.vcf');
I get the following error:
Can't locate object method "categories" via package "vCard" at tmp2.pl line 6.
What is the best way to get other nodes like CATEGORIES in my vcard file?
BTW: RFC6350 defines it... https://www.rfc-editor.org/rfc/rfc6350#section-6.7.1
There is https://metacpan.org/pod/Text::vCard::Precisely which seems to be more compliant with RFC6350:
use Text::vCard::Precisely;
my $vcard = Text::vCard::Precisely->new( version => '4.0' );
$vcard->n(['John','Doe']);
$vcard->categories([qw/Cat_01 Cat_02 Cat_03/]);
print $vcard->as_string();
prints:
BEGIN:VCARD
VERSION:4.0
N:John;Doe;;;
CATEGORIES:Cat_01,Cat_02,Cat_03
END:VCARD

SharePoint Office365 Powershell Webpart AllItems.aspx

Using powershell, add webpart (image) to the list view page, e.g. AllItems.aspx.
This code is ok when I adding webpart to sitepage but what/how can do the same things in list
$mySite = Get-PnPClientSidePage -Identity "TestWP.aspx"
$jsonProp = '{
"imageSourceType":0,
"imageSource":"https://MMMMMM.sharepoint.com/sites/pwa/SiteAssets/img01.jpg",
"captionText":" ",
"altText":" ",
"linkUrl":"",
"overlayText":"",
"fileName":"",
"siteId":"",
"webId":"",
"listId":"",
"uniqueId":"",
"imgWidth":"100%",
"imgHeight":"100%"
}'
Add-PnPClientSideWebPart -Page $mySite -Section 1 -Column 1 -Order 1 -DefaultWebPartType Image -WebPartProperties $jsonProp
E.g. in the AllItems.aspx view -> edit page -> Insert -> Image
or Add a Web Part.
example in the link.
img01
img02
coffee, a little break and I got it
first manually adding a web part to the test page then download webpart in xml format
# get xml
$imgWebPart = Get-PnPWebPartXml -ServerRelativePageUrl "/sites/pwa/Lists/TestList03/AllItems.aspx" -Identity "Image Viewer"
Add-PnPWebPartToWebPartPage -ServerRelativePageUrl "/sites/pwa/Lists/TestList03/aa.aspx" -Xml $imgWebPart -ZoneId Main -ZoneIndex 0
sorry for the confusion.

pass json as parameter in power shell script

I have made a function for creating new xml node.there are two parameters in my function on is a existing xml file reference and second one is element value.while running the script its showing an error
code
function createProviderNode($xmlData,$propertyValue){
Write-Host 'inside createProviderNode'
Write-Host ($propertyValue)
#[xml]$xmlData = get-content E:\powershell\data.xml
$newProviderNode = $xmlData.CreateNode("element","provider","")
$newProviderNode.SetAttribute("name",$propertyValue)
$xmlData.SelectSingleNode('providers').AppendChild($newProviderNode)
$xmlData.save("E:\powershell\data.xml")
}
did i miss anything in this code?
The error message implies that while you expected $xmlData to contain an object of type [xml] (System.Xml.XmlDocument) - i.e., an XML document - in reality it was a string ([string]).
In other words: When you called your createProviderNode function, the 1st argument you passed was a string, not an XML document (of type [xml]).
Typing your $xmlData parameter variable as [xml] solves this problem, as that will implicitly covert even a string argument to an XML document on demand - if possible.
A simplified example, using a script block in lieu of a function:
$xmlString = #'
<?xml version="1.0"?><catalog><book id="bk101"><title>De Profundis</title></book></catalog>
'#
# Note how $xmlData is [xml]-typed.
& { param([xml] $xmlData) $xmlData.catalog.book.title } $xmlString
The above yields De Profundis, demonstrating that the string argument was converted to an [xml] instance (which - thanks to PowerShell's type adaptation magic - makes the element names available as direct properties).
It is then safe to call the .CreateNode() method on $xmlData.
Well, you don't show your original XML format.
Why did you comment out that Get-Content? it will not work without it.
So, if we take the below example, it works as expected.
# Simple XML version
$SimpleXml = $null
$SimpleXml = #"
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<name>Apple</name>
<size>1234</size>
</configuration>
"#
# New node code
[xml]$XmlDoc = Get-Content -Path variable:\SimpleXml
$runtime = $XmlDoc.CreateNode("element","runtime","")
$generated = $XmlDoc.CreateNode("element","generatePublisherEvidence","")
$generated.SetAttribute("enabled","false")
$runtime.AppendChild($generated)
$XmlDoc.configuration.AppendChild($runtime)
$XmlDoc.save("$pwd\SimpleXml.xml")
Get-Content -Path "$pwd\SimpleXml.xml"
# Which creates this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<name>Apple</name>
<size>1234</size>
<runtime>
<generatePublisherEvidence enabled="false" />
</runtime>
</configuration>
Also Write-Host is never needed unless you are coloring screen output.
Write-Output is the default and automatically write to the screen, whether you specify Write-Output or not.
So, all of these to the same thing - output to the screen.
$SomeString = 'hello'
Write-Host $SomeString
Write-Output $SomeString
'hello'
"hello"
$SomeString
"$SomeString"
($SomeString)
("$SomeString")
$($SomeString)
# Results
hello
hello
hello
hello
hello
hello
hello
… yet, it's your choice.

Parsing XML and ignoring sections with powershell

I want to parse out the key fields and Data table information from here with PowerShell.
I only want the datatable name if there is a keyfield so in the example below I do not want CC:Attribute.
I also want to output things to a text file.
I want to have a text file that is created that holds the Data table name & Access as well as all the key fields and what they are.
This is the code I have so far:
[xml]$global:xmldata = get-content "C:\hackathon\Mfg.xml"
$xmldata2 = $xmldata.SchemaPackage.Tables
$SField = $xmldata2.DataTable.KeyFields | %{$_.StringField}
$Reffield = $xmldata2.DataTable.KeyFields | %{$_.ReferenceField}
$table = $xmldata2 | %{$_.DataTable}
Xml File:
<?xml version="1.0" encoding="utf-8"?>
<SchemaPackage Namespace="Mfg" xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DataTable Name="CC::Attribute">
<DataFields>
</DataFields>
</DataTable>
<DataTable Name="PlannerCode" Access="WW">
<Licenses>Manufacturing, DemandManagement</Licenses>
<Flags>
</Flags>
<KeyFields>
<StringField Name="Value"/>
<ReferenceField Name="Site" Target="Core::Site" SetField="PlannerCodes"/>
</KeyFields>
<DataFields>
<StringField Name="Description"/>
</DataFields>
</DataTable>
</SchemaPackage>
Despite the edit you made, I can only get your XML to validate if I modify it slightly (cleaning the opening XML tag and removing the SchemaPackage namespace). Regardless,
if you're experiencing no issues with your XML import then it's fine.
Here I'm just constructing the XML object from a herestring because I haven't got it in a file on disk.
[xml]$xmldata = #"
<xml>
<DataTable Name="CC::Attribute">
<DataFields>
</DataFields>
</DataTable>
<DataTable Name="PlannerCode">
<Licenses>Manufacturing, DemandManagement</Licenses>
<Flags>
</Flags>
<KeyFields>
<StringField Name="Value"/>
<ReferenceField Name="Site" Target="Core::Site" SetField="PlannerCodes"/>
</KeyFields>
<DataFields>
<StringField Name="Description"/>
</DataFields>
</DataTable>
</xml>
"#
# Filter DataTable nodes for those with a KeyFields child node.
$DataTablesWithKeyFields = $xmldata.xml.DataTable | Where-Object { $_.KeyFields }
$DataTableName = $DataTablesWithKeyFields.Name
$StringFieldData = $DataTablesWithKeyFields.KeyFields.ReferenceField
$ReferenceFieldData = $DataTablesWithKeyFields.KeyFields.ReferenceField
I'm not sure if that's what you're after. $DataTablesWithKeyFields could be an array depending on your XML file so you may need to loop it to extract the information you require.
Since we're working with XML, one of the querying options is XPath!
You can select only DataTable nodes that have a KeyFields child with the following XPath expression:
/SchemaPackage/DataTable[KeyFields]
You can use Select-Xml:
Select-Xml -Path C:\hackathon\Mfg.xml -XPath /SchemaPackage/DataTable[KeyFields] |Select-Object -Expand Node
or pass the expression as an argument to the SelectSingleNodes() method:
[xml]$xmldata = Get-Content C:\hackathon\Mfg.xml
$xmldata.SelectNodes('/SchemaPackage/DataTable[KeyFields]')