Ignore child order while comparing the xml nodes - c#

I have two xml document such as:
aDoc.xml:
<update id="1293">
<abc>.....</abc>
<xyz>....</xyz>
<components>
<component name="C1">
<files source="s1" target="t1">
<file>**file2**</file>
<file>**file1**</file>
</files>
</component>
</components>
</update>
bDoc.xml:
<update id="1293">
<abc>.....</abc>
<xyz>....</xyz>
<components>
<component name="C1">
<files source="s1" target="t1">
<file>**file1**</file>
<file>**file2**</file>
</files>
</component>
</components>
</update>
what i have tried so far is:
var DiffInA = aDoc.Descendants("component").Cast<XNode>().Except(bDoc.Descendants("component").Cast<XNode>(), new XNodeEqualityComparer());
the above line returns the output as below:
<component name="C1">
<files source="s1" target="t1">
<file>file2</file>
<file>file1</file>
</files>
(the node which is present in aDoc but not part of bDoc)
But if you look at both the xml files the component C1 is same only the order in which the tag appears is different.
Is there any way to achieve this using linq to xml.(i dont want to use XmlDiff or other Api's.)

Related

Merging issue in two xml documents using XDocument

The existing XML file(test.xml) content is as under
<manifest xmlns:imsmd="http://ltsc.ieee.org/xsd/LOM">
<resources>
<resource>
<file href="default.xml">
<metadata>
<imsmd:lom />
</metadata>
</file>
</resource>
</resources>
</manifest>
What I need is to add new node so that the final output resembles:
<manifest xmlns:imsmd="http://ltsc.ieee.org/xsd/LOM">
<resources>
<resource>
<file href="default.xml">
<metadata>
<imsmd:lom />
</metadata>
</file>
<file href="testimg.png">
<metadata>
<imsmd:lom />
</metadata>
</file>
</resource>
</resources>
</manifest>
My try so far (though not entirely correct is as under)
XNamespace ns = #"http://ltsc.ieee.org/xsd/LOM";
XNamespace lomns = ":lom";
var doc = XDocument.Load(#"D:\test.xml");
var result = new XDocument(
new XElement(ns + "manifest",
new XElement("file", new XAttribute("href", "testimg.png"),
new XElement("metadata", new XElement(lomns + "imsmd"))
)
)
);
//merge
doc.Root.Add(result.Root.Elements());
whose output is
<manifest xmlns:imsmd="http://ltsc.ieee.org/xsd/LOM">
<resources>
<resource>
<file href="default.xml">
<metadata>
<imsmd:lom />
</metadata>
</file>
</resource>
</resources>
<file href="testimg.png">
<metadata>
<imsmd xmlns=":lom" />
</metadata>
</file>
</manifest>
Code is adding new element to the root, but as per your required output you mentioned a new element(file) should be resource.
Locate the element resource in your xml and then add the element.
doc.Descendants("resource")
.ElementAt(0)
.Add(new XElement("file", new XAttribute("href", "testimg.png"),
new XElement("metadata", new XElement(doc.Root.GetNamespaceOfPrefix("imsmd")+ "lom"))));
Output:
<manifest xmlns:imsmd="http://ltsc.ieee.org/xsd/LOM">
<resources>
<resource>
<file href="default.xml">
<metadata>
<imsmd:lom />
</metadata>
</file>
<file href="testimg.png">
<metadata>
<imsmd:lom />
</metadata>
</file>
</resource>
</resources>
</manifest>
Check this Demo

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.

XDocument.Descendants() returns NullReferenceException : Object reference not set to an instance of an object

I have some difficulties to retrieve some datas in my XML file.
This is what my XML looks like:
<?xml version="1.0" encoding="windows-1252"?>
<hexML version="0.9">
<head>
<title><![CDATA[Title ]]></title>
<description/>
<ftm date="2014-09-24T16:34:37 CET"/>
</head>
<body>
<press_releases>
<press_release id="1796257" language="fr" type="5">
<published date="2014-06-19T11:55:09 CET"/>
<categories>
<category id="75" label="French" keywords="language"/>
</categories>
<headline><![CDATA[Test Release for Website 3]]></headline>
<main><![CDATA[TEXT XML DETAILLE]]></main>
<footer><![CDATA[]]></footer>
<files>
<file id="618383" format="pdf" type="Regular Attachment">
<file_headline><![CDATA[Test Attachment]]></file_headline>
<location><![CDATA[http://test.html1796257/618383.pdf]]></location>
</file>
</files>
<location href="/S/151406/1796257.xml"/>
</press_release>
</press_releases>
</body>
</hexML>
i try to get this data : http://test.html1796257/618383.pdf (in the "files" tag)
This is what i tried so far :
string Linkpdf = (from c in DetailXml.Descendants("files")
select c.Element("location").Value).Single();
This returns me the exception mentionned above.
Thanks for your help
If the XML was indented properly :
<files>
<file id="618383" format="pdf" type="Regular Attachment">
<file_headline><![CDATA[Test Attachment]]></file_headline>
<location><![CDATA[http://test.html1796257/618383.pdf]]></location>
</file>
</files>
you'll be able to see clearly that <location> is direct child of <file> element within <files> :
string Linkpdf = (from c in DetailXml.Descendants("files")
select c.Element("file").Element("location").Value).Single();

WiX to install EventSource

I created my event source based on this example. My event source looks like this:
[EventSource(Name = "Samples-EventSourceDemos-EventLog")]
public sealed class MinimalEventSource : EventSource
{
public static MinimalEventSource Log = new MinimalEventSource();
[Event(1, Message = "{0} -> {1}", Channel = EventChannel.Admin)]
public void Load(long baseAddress, string imageName)
{
WriteEvent(1, baseAddress, imageName);
}
}
The example use code to simulate install/uninstall process. From some other SO questions, I saw another example of installing event source using event message file.
But it is missing some good examples how to install/register the EventSource that defined by manifests. I am investigating using CustomAction to do something like:
wevtutil.exe im <EtwManifestManFile> /rf:"EtwManifestDllFile" /mf:"EtwManifestDllFile"
but wondering if you have any suggestions?
Figured out after some search. In the WixUtilExtension, there is build-in support. After referencing it and adding namespace, it is pretty easy.
Here are the changes in the Product.wxs:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
...
<Component Id="etwManifest.dll">
<File Id="etwManifest.dll" KeyPath="yes"
Source="$(var.SampleClassLibrary.TargetDir)\SampleClassLibrary.Samples-EventSourceDemos-EventLog.etwManifest.dll" />
</Component>
<Component Id="etwManifest.man">
<File Id="etwManifest.man" KeyPath="yes"
Source="$(var.SampleClassLibrary.TargetDir)\SampleClassLibrary.Samples-EventSourceDemos-EventLog.etwManifest.man">
<util:EventManifest MessageFile="[etwManifest.dll]" ResourceFile="[etwManifest.dll]"></util:EventManifest>
</File>
</Component>
</Wix>
The only trick I had to do is reduce the length of component Id and File Id (used to match with the file names) to avoid the following error: Error 25540. There was a failure while configuring XML files.
For me, the sollutions was to add permission to both files, the .dll and the .man. (https://stackoverflow.com/a/32727624/5500092)
<util:PermissionEx User="Everyone" ReadPermission="yes" ReadAttributes="yes" ReadExtendedAttributes="yes" />
I also had to add the full path to correctly registrate the manifest file. When i didn't do that, the manifest file still refer to the bin/release folder of my visual studio solution.
<util:EventManifest MessageFile="[INSTALLFOLDER]SampleClassLibrary.Samples-EventSourceDemos-EventLog.etwManifest.dll" ResourceFile="[INSTALLFOLDER]SampleClassLibrary.Samples-EventSourceDemos-EventLog.etwManifest.dll"/>
Code:
<DirectoryRef Id="INSTALLFOLDER">
<Component Id="etwManifest.dll" Guid="PUT-GUID-HERE">
<File Id="etwManifest.dll" KeyPath="yes" Source="$(var.SampleClassLibrary.TargetDir)\SampleClassLibrary.Samples-EventSourceDemos-EventLog.etwManifest.dll" >
<util:PermissionEx User="Everyone" ReadPermission="yes" ReadAttributes="yes" ReadExtendedAttributes="yes" />
<util:PermissionEx User="Administrators" ReadPermission="yes" ReadAttributes="yes" ReadExtendedAttributes="yes"/>
</File>
</Component>
<Component Id="etwManifest.man" Guid="PUT-GUID-HERE">
<File Id="etwManifest.man" KeyPath="yes" Source="$(var.SampleClassLibrary.TargetDir)\SampleClassLibrary.Samples-EventSourceDemos-EventLog.etwManifest.man" >
<util:PermissionEx User="Everyone" ReadPermission="yes" ReadAttributes="yes" ReadExtendedAttributes="yes"/>
<util:PermissionEx User="Administrators" ReadPermission="yes" ReadAttributes="yes" ReadExtendedAttributes="yes"/>
<util:EventManifest MessageFile="[INSTALLFOLDER]SampleClassLibrary.Samples-EventSourceDemos-EventLog.etwManifest.dll" ResourceFile="[INSTALLFOLDER]SampleClassLibrary.Samples-EventSourceDemos-EventLog.etwManifest.dll"/>
</File>
</Component>
</DirectoryRef>
Using WiX Toolset v3.10
(Please do correct me if my English is bad)

Removing attributes from elements

I will start off with the code...
private static void File()
{
wixFile = XDocument.Load(filePath);
var fileElements = from file in wixFile.Descendants(GetWixNamespace() + "File")
select file;
foreach (var file in fileElements)
{
if(file.Attributes("Name").Any())
file.Attribute("Name").Remove();
}
wixFile.Save(filePath);
}
I actually check for quite a few attributes in the list and remove or correct them, but just to keep it short I took everything out except for one example of what I was doing. The problem that I am having is that this code is not removing the Name attribute from anything like I would expect it. When I put a break point in and watch it the "file" is getting updated as expected, but the changes are not going over to the wixFile when I save (or during the editing either). I am not entirely sure what I am missing here so any help would be greatly appreciated.
EDIT:
Here is a snippet of the code that is being changed:
<?define ApplicationPath=\\dwdata\develope\DocuWare\DW5\Mast_dsk\?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Directory Id="DATADIR" Name="data">
<Directory Id="mysql" Name="mysql">
<Component Id="procs_priv.MYI" Guid="{1148181A-4818-434F-B2D1-E4B417586168}">
<File Id="procs_priv.MYI" Name="procs_priv.MYI" KeyPath="yes" Source="$(var.ApplicationPath)Common\MySql\Server\data\mysql\procs_priv.MYI" />
</Component>
<Component Id="procs_priv.MYD" Guid="{A6688F48-71AF-4242-B6D0-CA69452A01B4}">
<File Id="procs_priv.MYD" Name="procs_priv.MYD" KeyPath="yes" Source="$(var.ApplicationPath)Common\MySql\Server\data\mysql\procs_priv.MYD" />
</Component>
<Component Id="procs_priv.frm" Guid="{3025C26C-8DFF-43D4-A62A-79E78D2D807D}">
<File Id="procs_priv.frm" Name="procs_priv.frm" KeyPath="yes" Source="$(var.ApplicationPath)Common\MySql\Server\data\mysql\procs_priv.frm" />
</Component>
<Component Id="proc.MYI" Guid="{FD4AA2E1-E059-4549-AE61-222878185A0A}">
<File Id="proc.MYI" Name="proc.MYI" KeyPath="yes" Source="$(var.ApplicationPath)Common\MySql\Server\data\mysql\proc.MYI" />
</Component>
<Component Id="proc.MYD" Guid="{12EE6EE8-AC44-4601-84C5-14B27CF9A3E6}">
<File Id="proc.MYD" Name="proc.MYD" KeyPath="yes" Source="$(var.ApplicationPath)Common\MySql\Server\data\mysql\proc.MYD" />
</Component>
<Component Id="proc.frm" Guid="{8A6F2928-5484-4B55-B75F-8475C684A091}">
<File Id="proc.frm" Name="proc.frm" KeyPath="yes" Source="$(var.ApplicationPath)Common\MySql\Server\data\mysql\proc.frm" />
</Component>
</Directory>
</Directory>
</Wix>
I am getting the exact same thing back as well. What I am trying to do is remove the "Name" attribute, but it just isn't working for whatever reason. The GetWiXNamespace() method returns the same namespace that is listed in the wix element as an XNamespace.
I'm going to read between the lines here and guess you are converting from an old version of WiX ( say 2.0 ) that required a File#Name attribute to a version ( say 3.0-3.6 ) that can infer this attribute and doesn't require it.
Here's some code that I just whipped up that I know works assuming the source xml is WiX 3.x. I'm not sure what is wrong with your code but perhaps the method that returns the namespace hasn't accounted for the url change.
XNamespace ns = "http://schemas.microsoft.com/wix/2006/wi";
var doc = XDocument.Load(#"C:\before.wxs");
var elements = from element in doc.Descendants( ns + "File")
where element.Attribute("Name") != null
select element;
foreach (var element in elements)
{
element.Attribute("Name").Remove();
}
doc.Save(#"C:\after.wxs");
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define SourceDir="."?>
<Module Id="YourModuleHere" Language="1033" Version="1.0.0.0">
<Package Id="31c7722e-c2a0-4328-92a2-eacd443c10a9" Manufacturer="YourCompanyHere" InstallerVersion="200" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="MergeRedirectFolder">
<Component Id="owc7CEF9B0C53324FC23404D2AAAB5D12B8" Guid="6898e947-fa51-8efb-bda4-2e256dea8ed1">
<File Id="owf7CEF9B0C53324FC23404D2AAAB5D12B8" Name="bfsvc.exe" Source="$(var.SourceDir)\Windows\bfsvc.exe" KeyPath="yes" />
</Component>
<Component Id="owc8C6EA26177072C0006EEF8265FEF72A4" Guid="91737806-0b20-24ad-9653-cca05b5778fb">
<File Id="owf8C6EA26177072C0006EEF8265FEF72A4" Name="explorer.exe" Source="$(var.SourceDir)\Windows\explorer.exe" KeyPath="yes" />
</Component>
</Directory>
</Directory>
</Module>
</Wix>

Categories