Converting graphml to image - c#

I have this script that creates a .graphml file, and it looks great in yEd (Link to software), but I'm trying to automate the extra step of having this file, opening it in a different program, doing some edits in there etc etc.
I was wondering if there was some way to automate this into a png image, preferably a hexagonal grid or Vornoi in C#, depending on whether or not each node is connected to exactly 6 or not.
The .graphml file structure looks as follows:
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<key id="d2" for="node" attr.name="value" attr.type="long" />
<key id="d1" for="node" attr.name="y" attr.type="long" />
<key id="d0" for="node" attr.name="x" attr.type="long" />
<graph edgedefault="directed">
<node id="(0, 1)">
<data key="d0">0</data>
<data key="d1">1</data>
<data key="d2">0</data>
</node>
.
.
.
<node id="(39, 38)">
<data key="d0">39</data>
<data key="d1">38</data>
<data key="d2">4</data>
</node>
<edge source="(0, 1)" target="(1, 1)"></edge>
<edge source="(0, 1)" target="(0, 2)"></edge>
.
.
.
<edge source="(39, 38)" target="(38, 39)"></edge>
</graph>
</graphml>
The value is a direct one-to-one mapping of the node's colour.
And the coordinates are in the following pattern if it were a regular hexagonal grid:
Hope this query makes sense!
Kind regards.

Related

Where are Visio Master Shape properties stored?

I have a program that parses the XML data of a Visio file. In this file there is a grouped shape consisting of several master shapes. Like so:
Each shape has a Property called Pin
Pin 1 is the default value saved in the master shape. When I unzip the Visio file and look at the XML data, the "Pin" property will not show up on pin 1, but it will be there for all the other pins.
<PageContents xmlns="http://schemas.microsoft.com/office/visio/2012/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xml:space="preserve">
<Shapes>
<Shape ID="2010" Type="Group" LineStyle="7" FillStyle="7" TextStyle="7" UniqueID="{B849B0B2-94FC-4CC7-843F-6A55BDBD37E6}">
<Cell N="PinX" V="8.484814432615094"/>
<...etc>
<Section N="Property">
<Row N="REF">
<Cell N="Value" V="X999" U="STR"/>
<...etc>
</Row>
</Section>
<Shapes>
<Shape ID="2" NameU="Pin.1994" IsCustomNameU="1" Name="Pin.1994" IsCustomName="1" Type="Group" Master="126" UniqueID="{216A72DB-F8E9-4C30-9C34-DE9A8448552B}">
<Cell N="PinX" V="0.07874015748031506" F="Sheet.1!Width*0.5"/>
<...etc>
<Shapes>
<Text callout and background shapes>
</Shapes>
</Shape>
<Shape ID="6" NameU="Pin.2002" IsCustomNameU="1" Name="Pin.2002" IsCustomName="1" Type="Group" Master="126">
<Cell N="PinX" V="0.07874015748031506" F="Sheet.1!Width*0.5"/>
<...etc>
<Section N="Property">
<Row N="Pin">
<Cell N="Value" V="2" U="STR"/>
</Row>
</Section>
<Shapes>
<Text callout and background shapes>
</Shapes>
</Shape>
</Shapes>
</Shape>
</Shapes>
</PageContents>
If I rename the "Pin" property to anything other than "1" the property will show up just like it does on Pin 2. I thought this was because it was stored in the Master Shape, but there is no "Property" tag in the master file either.
<MasterContents xmlns="http://schemas.microsoft.com/office/visio/2012/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xml:space="preserve">
<Shapes>
<Shape ID="5" Type="Group" LineStyle="0" FillStyle="0" TextStyle="0" UniqueID="{F811FFC2-FDBC-4EFF-97CF-13F5FFBC677C}">
<Cell N="PinX" V="0"/>
<...etc>
<Section N="User">...</Section>
<Section N="Geometry">...</Section>
<Shapes>
<Shape ID="6" NameU="Text callout" IsCustomNameU="1" Name="Text callout" IsCustomName="1" Type="Group" LineStyle="3" FillStyle="3" TextStyle="3" UniqueID="{4CF654FB-78A6-413C-A551-70A86FC63644}">...</Shape>
</Shapes>
</Shapes>
</MasterContents>
Since Visio is displaying the value it must get the property name and value from somewhere but i have no idea where it does that.
When i parse the file i look for the "Pin" property and extract data from other properties that are in the shape, but when the "Pin" property is not present it will skip all that information for every Pin 1 in the document.
I will attach the complete xml files here if anyone wants to have a look at them.
Property renamed to "1 "
Property missing
Master126
*Edit: Zipfile with all XML files
*Edit2: VSDX file
Thanks for the vsdx, that's helpful.
As you highlighted, the Pin Shape Data row in 'Pin1' shape doesn't show up in the instance shape xml (PageContents) as it is an inherited value from its master. The other two shapes, having local values, are reflected within the instance xml.
I think the problem you're having is you're looking at the wrong master and so not finding the data you're after.
The way to trace this back is if you look at the page xml (page1.xml) you'll see that the Pin shape is based on master id '6':
[Note - I've cut out quite a lot of the xml in the following snippets to give a clearer picture of the structure for the file.]
<PageContents>
<Shapes>
<Shape ID='17' Type='Group' LineStyle='7' FillStyle='7' TextStyle='7'>
<Shapes>
<Shape ID='5' NameU='Pin' Name='Pin' Type='Group' Master='6'>
Now you can look in the masters collection (masters.xml) and will see that the master with an ID attribute of 6 (the 'Pin' master) has a rel id of 'rId2':
<Masters>
<Master ID='2' NameU='Dynamic connector' IsCustomNameU='1' Name='Dynamic connector' IsCustomName='1'>
<Rel r:id='rId1'/>
</Master>
<Master ID='6' NameU='Pin' IsCustomNameU='1' Name='Pin' IsCustomName='1'>
<Rel r:id='rId2'/>
</Master>
Now you've got the correct rel id you and lookup the correct master declaration in master.xml.rels where you'll see that rel id 'rId2' points to master2.xml:
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId3" Type="http://schemas.microsoft.com/visio/2010/relationships/master" Target="master3.xml"/>
<Relationship Id="rId2" Type="http://schemas.microsoft.com/visio/2010/relationships/master" Target="master2.xml"/>
<Relationship Id="rId1" Type="http://schemas.microsoft.com/visio/2010/relationships/master" Target="master1.xml"/>
<Relationship Id="rId5" Type="http://schemas.microsoft.com/visio/2010/relationships/master" Target="master5.xml"/>
<Relationship Id="rId4" Type="http://schemas.microsoft.com/visio/2010/relationships/master" Target="master4.xml"/>
</Relationships>
So your final stop is to head off to master2.xml where you should find that the top level shape (id 5) has a Shape Data row named 'Pin' and a value of '1':
<MasterContents>
<Shapes>
<Shape ID='5' NameU='Pin.473' IsCustomNameU='1' Name='Pin.473' IsCustomName='1' Type='Group'>
<Section N='Property'>
<Row N='Pin'>
<Cell N='Value' V='1' U='STR'/>
<Cell N='Prompt' V='' F='No Formula'/>
<Cell N='Label' V='Pin'/>
<Cell N='Format' V='' F='No Formula'/>
<Cell N='SortKey' V='' F='No Formula'/>
<Cell N='Type' V='0'/>
<Cell N='Invisible' V='0' F='No Formula'/>
<Cell N='Verify' V='0' F='No Formula'/>
<Cell N='DataLinked' V='0' F='No Formula'/>
<Cell N='LangID' V='sv-SE'/>
<Cell N='Calendar' V='0' F='No Formula'/>
</Row>
</Section>
I'm guessing that you're treating the vsdx as a zip and that you're missing out on the System.IO.Packaging namespace which will help you with navigating the package relationships. I'll add this link just in case:
Manipulate the Visio file format programmatically

Passing XML multi level data as parameter and using in stored procedure

I have XML format data which I will pass from a .net application.
In the SQL Server stored procedure, this data is passed in as a XML parameter. I want to read and save the data in the required tables, say TblOrder and TblItem.
In XML, there will be multiple orders. Each order contains one or several items accordingly.
Structure on which operation need to be implemented:
<?xml version="1.0" encoding="UTF-8"?>
<Orders>
<Order>
<B2>B2**ABIJ**0000884443**PP</B2>
<CreateBy null="true" />
<CreateDate>/Date(1485150414358)/</CreateDate>
<CurrencyId>1</CurrencyId>
<CustomerId>13</CustomerId>
<DeliveryAddress>LIBERTY PRESS LLC</DeliveryAddress>
<DeliveryCity>SPRINGVILLE UT 84663</DeliveryCity>
<DeliveryCityId>0</DeliveryCityId>
<DeliveryDate>/Date(1478750400000)/</DeliveryDate>
<DeliveryId>14</DeliveryId>
<DeliveryState>UT</DeliveryState>
<DeliveryStateId>16</DeliveryStateId>
<DeliveryType>Delivery</DeliveryType>
<EquipmentId>4</EquipmentId>
<Items>
<Item>
<CSA>false</CSA>
<CTPAT>false</CTPAT>
<CommodityItem>General Freight</CommodityItem>
<CommodityItemId>0</CommodityItemId>
<CustCommodityItem null="true" />
<FAST>false</FAST>
<Hazmat>false</Hazmat>
<Height null="true" />
<IsActive>false</IsActive>
<ItemId>0</ItemId>
<ItemName>Item A</ItemName>
<Length null="true" />
<Make null="true" />
<Mass null="true" />
<MassUnit null="true" />
<Model null="true" />
<OrderId>0</OrderId>
<PIP>false</PIP>
<PilotCar>false</PilotCar>
<ReeferTemp null="true" />
<Tarp>false</Tarp>
<TrailerType null="true" />
<TruckType null="true" />
<VIN null="true" />
<Width null="true" />
<Year null="true" />
</Item>
</Items>
<L11>L11*SYL884443*BM</L11>
<LastUpdate>/Date(1485150414358)/</LastUpdate>
</Order>
<Order>
...
<Items>
<Item>
...
</Item>
</Order>
</Orders>
Steps I want to achieve are:
Read XML parameter from the stored procedure, which is passed from the .net application.
Loop through the XML and save data in the TblOrder and TblItem tables
Going through the article follows :
Pass-XML-parameter-to-Stored-Procedure
How to loop and parse xml parameter in sql server stored procedure
I got the Idea to access very first level (in my case Order of Orders).
Moving forward having issue accessing the second level which will be again a collection (in my case Item of Items of Order).
Thanks in advance for your support
You have two approaches:
You can pass the XML as-is into a Stored Procedure and do all the hard work in T-SQL
You can shredd the XML within C#, fill appropriate data objects and use classical data storage.
From your question I take, that you'd prefer to pass this into a stored procedure as XML parameter. There are some things to know:
C# uses 16-bit-unicode internally and so does SQL Server's XML. But you will not be able to cast this unicode string to XML as long as there is encoding="UTF-8" included... You might pass this as VARCHAR(MAX) (not NVARCHAR(MAX)!), but this could lead you in troubles if there are sepcial characters involved. Best was, to cut the first line (the <?xml ...?> declaration) away completely.
Your XML is not created correctly. Is this under you control? If you include null="true" (there's no need for normally!), you should do this with the xsi-namespace. And date/time values within XML should be ISO8601. Your values (like /Date(1485150414358)/) are no format SQL Server will be able to cast directly...
Nevertheless I see multi <Order>-elements and multi <Item>-elements. You could read them as follows:
DECLARE #xml XML=
N'<Orders>
<Order>
<B2>B2**ABIJ**0000884443**PP</B2>
<CreateBy null="true" />
<CreateDate>/Date(1485150414358)/</CreateDate>
<CurrencyId>1</CurrencyId>
<CustomerId>13</CustomerId>
<DeliveryAddress>LIBERTY PRESS LLC</DeliveryAddress>
<DeliveryCity>SPRINGVILLE UT 84663</DeliveryCity>
<DeliveryCityId>0</DeliveryCityId>
<DeliveryDate>/Date(1478750400000)/</DeliveryDate>
<DeliveryId>14</DeliveryId>
<DeliveryState>UT</DeliveryState>
<DeliveryStateId>16</DeliveryStateId>
<DeliveryType>Delivery</DeliveryType>
<EquipmentId>4</EquipmentId>
<Items>
<Item>
<CSA>false</CSA>
<CTPAT>false</CTPAT>
<CommodityItem>General Freight</CommodityItem>
<CommodityItemId>0</CommodityItemId>
<CustCommodityItem null="true" />
<FAST>false</FAST>
<Hazmat>false</Hazmat>
<Height null="true" />
<IsActive>false</IsActive>
<ItemId>0</ItemId>
<ItemName>Item A</ItemName>
<Length null="true" />
<Make null="true" />
<Mass null="true" />
<MassUnit null="true" />
<Model null="true" />
<OrderId>0</OrderId>
<PIP>false</PIP>
<PilotCar>false</PilotCar>
<ReeferTemp null="true" />
<Tarp>false</Tarp>
<TrailerType null="true" />
<TruckType null="true" />
<VIN null="true" />
<Width null="true" />
<Year null="true" />
</Item>
</Items>
<L11>L11*SYL884443*BM</L11>
<LastUpdate>/Date(1485150414358)/</LastUpdate>
</Order>
</Orders>';
--the query
SELECT --elements of Order
o.value(N'(B2)[1]',N'nvarchar(max)') AS B2
--very strange date-format...
,o.value(N'(CreateDate)[1]',N'nvarchar(max)') AS CreateDate
--typed INT
,o.value(N'(CurrencyId)[1]',N'int') AS CurrencyId
--more like this
--elements of Item
,i.value(N'(CSA)[1]',N'nvarchar(max)') AS CSA
--There's no need for *null="true"*
--Query the "/text()" and the empty element will be NULL
,CASE WHEN i.value(N'(CustCommodityItem/#null)[1]',N'nvarchar(max)')=N'true' THEN NULL ELSE i.value(N'(CustCommodityItem)[1]',N'nvarchar(max)') END AS CustCommodityItem_complicated
,i.value(N'(CustCommodityItem)[1]',N'nvarchar(max)') AS CustCommodityItem_empty
,i.value(N'(CustCommodityItem/text())[1]',N'nvarchar(max)') AS CustCommodityItem_null
FROM #xml.nodes(N'/Orders/Order') AS A(o)
OUTER APPLY o.nodes(N'Items/Item') AS B(i)

Unable to use xpath as expected on document

I have the following XML document
<?xml version="1.0" encoding="utf-8"?>
<GovTalkMessage xmlns="http://www.govtalk.gov.uk/CM/envelope">
<EnvelopeVersion>2.0</EnvelopeVersion>
<Header>
<MessageDetails>
<Class>
</Class>
<Qualifier>request</Qualifier>
<Function>submit</Function>
<CorrelationID />
<Transformation>
</Transformation>
<GatewayTest>0</GatewayTest>
</MessageDetails>
<SenderDetails>
<IDAuthentication>
<SenderID>
</SenderID>
<Authentication>
<Method>clear</Method>
<Role>principal</Role>
<Value></Value>
</Authentication>
</IDAuthentication>
</SenderDetails>
</Header>
<GovTalkDetails>
<Keys>
<Key Type="TaxOfficeNumber">
</Key>
<Key Type="TaxOfficeReference">
</Key>
</Keys>
<TargetDetails>
<Organisation>IR</Organisation>
</TargetDetails>
<ChannelRouting>
<Channel>
<URI>
</URI>
<Product></Product>
<Version>
</Version>
</Channel>
<timestamp>
</timestamp>
</ChannelRouting>
</GovTalkDetails>
<Body>
<IRenvelope xmlns="">
<IRheader>
<Keys>
<Key Type="TaxOfficeNumber">
</Key>
<Key Type="TaxOfficeReference">
</Key>
</Keys>
<PeriodEnd>
</PeriodEnd>
<DefaultCurrency>GBP</DefaultCurrency>
<IRmark>
</IRmark>
<Sender>Employer</Sender>
</IRheader>
</IRenvelope>
</Body>
</GovTalkMessage>
and I'm loading it into a XMLDocument using the XMLDocument.load().
Now when I run xpath queries against it they are not responding as I would expect and I cant seem to find out why, I have used XPath Visualiser tool and it shows that for example //Keys/Key should return 4 nodes
When I run the following c#
document.SelectNodes(#"//Keys/Key") it returns 2 nodes not the expected 4.
Also when I run the following
document.SelectNodes(#"//Header") it returns 0 nodes
Also running
document.SelectNodes(#"GovTalkMessage") returns 0 nodes.
All suggestions and help greatfully received.
Thanks
Ben
XPath needs namespaces. The tags you are trying to select are in one, so you have to tell the select where to look.

LINQ for XML, having trouble reading in multiple elements of varying occurences

Let's say I have the following XML file below. My question is, how to I account for a different number of name elements (child of environment element) when querying using LINQ. I can read the file and even query when there are the same number of name elements (for example, they all have 3). My goal is to populate an object that has a list caled environment with the names in the XML file. Any help would be appreciated.
<database type="prod">
<name>DB1</name>
<server>
<name>prodserver.net</name>
</server>
<connection>
<name>u1</name>
<password>b1</password>
</connection>
<environment>
<name>test1</name>
<name>test2</name>
<name>test3</name>
</environment>
</database>
<database type="dev">
<name>DB2</name>
<server>
<name>devserver.net</name>
</server>
<connection>
<name>u11</name>
<password>b11</password>
</connection>
<environment>
<name>test1</name>
<name>test2</name>
<name>test3</name>
<name>test4</name>
<name>test5</name>
</environment>
</database>
Or maybe to make it even easier, let's say I have the following
<student name="A" class="1">
<classes>
Math
</classes>
</student>
<student name="B" class="2">
<classes>
Programming
</classes>
</student>
And I run the following code:
var students = doc.Root
.Elements("student")
.Select(x => new Student
{
Name = (string)x.Attribute("name"),
Class = (string)x.Attribute("class"),
Type = (string)x.Elements("classes").Single().Value
})
.ToList();
It works fine, but when I add one more classes element, it breaks:
<student name="A" class="1">
<classes>
Math
</classes>
<classes>
Java
</classes>
</student>
<student name="B" class="2">
<classes>
Programming
</classes>
</student>
It's not really clear what you mean... assuming you have (say) an Environment type with a constructor accepting a List<string> as the names, you'd use:
// If element is the <environment> element
Environment = new Environment(element.Elements("name")
.Select(x => x.Value)
.ToList());

What is the best method to manipulate xml files?

I want to manipulate XML files.
...
<Document Id="1091">
<Indexes>
<Index Name="MODD" Value="aaa" />
<Index Name="DDAT" Value="bbb" />
<Index Name="CDAT" Value="ccc" />
<Index Name="MDAT" Value="ddd" />
<Index Name="DOCN" Value="eee" />
<Index Name="STAT" Value="fff" />
...
</Indexes>
</Document>
<Document Id="2088">
...
I have retrieve the value of some index randomly. I would avoid the loop on all the indexes. What is the tool you advise me to use and why?
load the file as a text file and use RegEx
load the xml file and use XPath
load the xml file and use Linq to Xml
generate the classes with xsd.exe or xsd2code
another approach
I'd go with LinqToXml. Good syntax and easy to use!

Categories