I am trying to store XPath of an XML attribute as a string in a separate file so that if XPath changes, I can easily modify the navigation to the attribute without changing code.
For example, in following XML:
<Result>
<Server = "main">
<Client id="1"></Client>
</Server>
</Result>
if I want to navigate to id attribute of Client element, I can have following string:
Result->Server->Client->id
I am not sure how in C# I can navigate using this string form of XPath and then, read the attribute value from the target XML.
Please help.
Harit
Well, firstly, your XML is a bit strange, with
<Server = "main">
Do you mean
<Server id="main">
But, regardless of that, you could just store the XPath directly instead of your string version. Like:
/Result/Server/Client[0]/#id
then you read the string from the file and pass it into something like:
public string GetClientIdString(string xPathString)
{
var doc = new XmlDocument();
doc.Load("SomeXml.xml");
return doc.DocumentElement.SelectSingleNode(xPathString).Value;
}
The issue becomes that you can't really store the XPath exactly how you would like if you plan on having more than one Client under Server. If you need that functionality, though, you could parse out your version of the XPath and do something like:
public IEnumerable<string> GetClientIdStrings(string elementXPath, string attribute)
{
var doc = new XmlDocument();
doc.Load(SomeXml.xml);
var clientIdStrings = new List<string>();
foreach(var node in doc.DocumentElement.SelectNodes(elementXPath))
{
clientIdStrings.Add(node.Attributes[attribute].Value);
}
return clientIdStrings;
}
Related
<TestCase Name="DEBUG">
<ActionEnvironment Name="Carved records indication">
<Define Name="_TestedVersionPath" Value="{CustomParam {paramName=PA tested version installer folder path}, {appName=PA installer}, {hint=\\ptnas1\builds\Temp Builds\Forensic\Physical Analyzer\PA.Test\UFED_Analyzer_17.02.05_03-00_6.0.0.128\EncryptedSetup}}"/>
<Define Name="_PathOfdata" Value="SharedData\myfolder\mydata.xml"/>
<ActionSet Name="DEBUG">
<Actions>
<SpecialAction ActionName="myactionname">
<CaseName>123</CaseName>
<UaeSendQueryValues>
<URL>192.168.75.133</URL>
<RestURL></RestURL>
<UserName>user1</UserName>
<Password>aaa</Password>
<PathOfQuery>_PathOfdata</PathOfQuery>
<Method>GET</Method>
<ParamsFromFile></ParamsFromFile>
</UaeSendQueryValues>
</SpecialAction>
</Actions>
</ActionSet>
</ActionEnvironment>
I have the above xml. i need to find every PathOfQuery tag, get the text of it (in the example _PathOfdata) and then go up in the xml tree and find the first Define tag who's name = to text of PathofQuery tag and get its value (in the example "SharedData\myfolder\mydata.xml")
then i would like to replace that value with another string.
i need to do this for each PathofQuery tag that appears in the xml (it could be more then one) and i want to find always the first apparition of the Define tag (could be more than one) when i travel the tree up from the point where the PathofQuery tag was found.
I want to do this on C Sharp
any help will be appreciated.
Let's assume string s holds the above Xml. Then the following code will work for you:
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(s);
XmlNode pathOfQuery = xDoc.SelectSingleNode("//PathOfQuery");
string pathOfQueryValue = pathOfQuery.InnerText;
Console.WriteLine(pathOfQueryValue);
XmlNode define = xDoc.SelectSingleNode("//Define[#Name='" + pathOfQueryValue + "']");
if(define!=null)
{
string defineTagValue = define.Attributes["Value"].Value;
Console.WriteLine(defineTagValue);
pathOfQuery.InnerText = defineTagValue;
Console.WriteLine(pathOfQuery.InnerText);
}
Ok, I have an xml document which is returned via a c# function and output via XSLT. In the XML document there is an encrypted string which I need to decrypt before output.
Basically, i need to run "encryptedstring" through a decrypting function in order get the real value.
XML Structure:
<root>
<order encryptedstring="676696969hjhig">
</root>
Outputting function:
XmlDocument xmlOrders = Data_Functions.Get_All_Orders();
xmlOutput.DocumentContent = xmlOrders.OuterXml;
I am assuming i need to loop through the XML document, get the value for each "encryptedstring", run that value through the decrypt function and re-inject it back into the xml document but am unsure of best way to go about that.
The decryption has to be done in the codebehind in c# by passing a string through decryptString();
With a bit of guidance from the question suggestion by #momar this was solved in the following way...
XmlNodeList aNodes = xmlOrders.SelectNodes("//root/order");
foreach (XmlNode aNode in aNodes)
{
XmlAttribute ccAttribute = aNode.Attributes["encryptedstring"];
string attValue= ccAttribute.Value;
string encKey = ConfigurationManager.AppSettings["EncryptionKey"];
string decrypt = Crypto.DecryptStringAES(attValue, encKey);
ccAttribute.Value = deencrypt;
}
xmlOutput.DocumentContent = xmlOrders.OuterXml;
I am trying to figure out how to use Linq to XML to read an XML file into my C# program. Here is the example for my question:
<node name="services" class="tridium.containers.ServiceContainer" module="coreRuntime" release="2.301.532.v1">
How do I access the name, class, module, and release information in this line? I tried .element("node").Name for the name field, but that just returns "node". All of the tutorials I can find are either too simplistic to deal with this, or deal with writing an XML file. Please help.
You can use this :
XElement rootelement = XElement.Load(#"path_to_your_file") ;
var name = rootElement.Attribute("name").Value ;
var classname = rootElement.Attribute("class").Value ;
var module = rootElement.Attribute("module").Value ;
If it is at the root, then
XDocument xdoc = XDocument.Load("data.xml");
var name= xdoc.Root.Attribute("name").Value;
var class= xdoc.Root.Attribute("class").Value;
var module= xdoc.Root.Attribute("module").Value;
Having trouble dealing with xml and to properly use it for my purpose. So i am creating a test method and one of the parameters is xml data and i am not sure how to pass it in.
Service
public IEnumerable<Submissions> CheckingOutForUserReview(string data)
{
var _submissions = DataContextManager.StoredProcs.CheckingOutForUserReview<SSubmissions>(data, s => new Submissions
{
QRCodeGUID = SubmissionsColumnMap.QRCodeGUID(s),
StoragePath = SubmissionsColumnMap.StoragePath(s),
UploadedByUsersID = SubmissionsColumnMap.UploadedByUsersID(s)
});
return _submissions;
}
Stored Proc:
public virtual IEnumerable<T> CheckingOutForUserReview<T>(string data, Func<IDataRecord, T> modelBinder)
{
SqlCommand _command = new SqlCommand("dbo.CheckingOutForUserReview");
_command.CommandType = CommandType.StoredProcedure;
_command.Parameters.Add(new SqlParameter { ParameterName = "Data", SqlDbType = SqlDbType.Xml, Value = data });
return DbInstance.ExecuteAs<T>(_command, modelBinder);
}
This is my TestMethod:
public void CheckingOutForUserReview()
{
string _data = #"<CheckingOutForUserReview xmlns:i=""www.w3.org/2001/XMLSchema-instance"" xmlns=""schemas.name.com/2013/03/Malt.Models"">
<Record>
<QRCodeID>2FAC636E-F96C-4465-9272-760BAF73C0DF</QRCodeID>
<SubmissionID>10B5236C-47FD-468D-B88D-D789CA0C663A</SubmissionID>
<UserID>1</UserID>
<Page>1</Page>
</Record>
</CheckingOutForUserReview>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(_data);
var _Svc = new SubmissionsService();
var _checkins = _Svc.CheckingOutForUserReview(doc.InnerXml);
}
UPDATE:
my CheckingOutForUserReview() method accepts a XmlDocument as i changed it to that in my stored procedure and with what i currently have it is giving an error that i have invalid arguments(System.Xml.XmlDocument) not sure if i messed up somewhere.
If this is a different way i am also open in trying new ways. Thanks for the help.
As I see there are two ways:
You should save your xml into an xml file by adding xml file in your
project then use it with XmlDocument using Load method like:
XmlDocument doc = new XmlDocument.Load(FileName);
...
...
var _checkins = _Svc.CheckingOutForUserReview(doc.innerXml);
Save your xml as a string literal and use it with XmlDocument using
LoadXml method like:
XmlDocument doc = new XmlDocument.LoadXml(stringThatContainsXml);
...
...
var _checkins = _Svc.CheckingOutForUserReview(doc.innerXml);
You can use XDocument and XElement classes as well but my focus on XmlDocument is that it will work for framework less than 3.5 too since XDocument and XElement is introduced in framework 3.5.
Also loading xml into a parser will help to filter out the invalid xml. (if mistakenly tried to use)
Another thing i have noticed in your snippet:
Assert.IsNotNull(_data);
It should come before the initialization of _Svc, because if there is no data in _data initialization doesn't make sense.
So your code looks like:
public void CheckingOutForUserReview()
{
string _data = "I want to pass in xml here";
Assert.IsNotNull(_data); <--------------- See the re-ordering
var _Svc = new SubmissionsService();
var _checkins = _Svc.CheckingOutForUserReview(_data);
}
Like I said in a comment, I think the best way to do this is to save the XML into a separate file.
If you don't want to do that, you can use verbatim string literal (note the double quotes):
string data = #"<CheckingOutForUserReview xmlns:i=""www.w3.org/2001/XMLSchema-instance"" xmlns=""schemas.name.com/2013/03/Malt.Models"">
<Record>
<QRCodeID>2FAC636E-F96C-4465-9272-760BAF73C0DF</QRCodeID>
<SubmissionID>10B5236C-47FD-468D-B88D-D789CA0C663A</SubmissionID>
<UserID>1</UserID>
<Page>1</Page>
</Record>
</CheckingOutForUserReview>";
I don't see what is the problem in passing any kind of strings as a parameter into a method
If your XML is generated from your code, you better have used a StringBuilder to build it to reduce creating new references while concatenating your string.
If your XML is originally from a file, pass the file path into your method, and open the document there. there are a lot of different ways to open and read XML documents, or loading a string to an XML document and deal with it as XML rather than a string.
Examples:
http://www.codeproject.com/Articles/24375/Working-with-XML
http://forum.codecall.net/topic/58239-c-tutorial-reading-and-writing-xml-files/
and finally from MSDN:
http://msdn.microsoft.com/en-us/library/aa288481%28v=vs.71%29.aspx
enjoy
Load function is already defined in xmlData class
public class XmlData
{
public void Load(XElement xDoc)
{
var id = xDoc.XPathSelectElements("//ID");
var listIds = xDoc.XPathSelectElements("/Lists//List/ListIDS/ListIDS");
}
}
I'm just calling the Load function from my end.
XmlData aXmlData = new XmlData();
string input, stringXML = "";
TextReader aTextReader = new StreamReader("D:\\test.xml");
while ((input = aTextReader.ReadLine()) != null)
{
stringXML += input;
}
XElement Content = XElement.Parse(stringXML);
aXmlData.Load(Content);
in load function,im getting both id and and listIds as null.
My test.xml contains
<SEARCH>
<ID>11242</ID>
<Lists>
<List CURRENT="true" AGGREGATEDCHANGED="false">
<ListIDS>
<ListID>100567</ListID>
<ListID>100564</ListID>
<ListID>100025</ListID>
<ListID>2</ListID>
<ListID>1</ListID>
</ListIDS>
</List>
</Lists>
</SEARCH>
EDIT: Your sample XML doesn't have an id element in the namespace with the nss alias. It would be <nss:id> in that case, or there'd be a default namespace set up. I've assumed for this answer that in reality the element you're looking for is in the namespace.
Your query is trying to find an element called id at the root level. To find all id elements, you need:
var tempId = xDoc.XPathSelectElements("//nss:id", ns);
... although personally I'd use:
XDocument doc = XDocument.Parse(...);
XNamespace nss = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner";
// Or use FirstOrDefault(), or whatever...
XElement idElement = doc.Descendants(nss + "id").Single();
(I prefer using the query methods on LINQ to XML types instead of XPath... I find it easier to avoid silly syntax errors etc.)
Your sample code is also unclear as you're using xDoc which hasn't been declared... it helps to write complete examples, ideally including everything required to compile and run as a console app.
I am looking at the question 3 hours after it was submitted and 41 minutes after it was (last) edited.
There are no namespaces defined in the provided XML document.
var listIds = xDoc.XPathSelectElements("/Lists//List/ListIDS/ListIDS");
This XPath expression obviously doesn't select any node from the provided XML document, because the XML document doesn't have a top element named Lists (the name of the actual top element is SEARCH)
var id = xDoc.XPathSelectElements("//ID");
in load function,im getting both id and and listIds as null.
This statement is false, because //ID selects the only element named ID in the provided XML document, thus the value of the C# variable id is non-null. Probably you didn't test thoroughly after editing the XML document.
Most probably the original ID element belonged to some namespace. But now it is in "no namespace" and the XPath expression above does select it.
string xmldocument = "<response xmlns:nss=\"http://schemas.microsoft.com/SQLServer/reporting/reportdesigner\"><action>test</action><id>1</id></response>";
XElement Content = XElement.Parse(xmldocument);
XPathNavigator navigator = Content.CreateNavigator();
XmlNamespaceManager ns = new XmlNamespaceManager(navigator.NameTable);
ns.AddNamespace("nss", "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner");
var tempId = navigator.SelectSingleNode("/id");
The reason for the null value or system returned value is due to the following
var id = xDoc.XPathSelectElements("//ID");
XpathSElectElements is System.xml.linq.XElment which is linq queried date. It cannot be directly outputed as such.
To Get individual first match element
use XPathSelectElement("//ID");
You can check the number of occurrences using XPathSelectElements as
var count=xDoc.XPathSelectElements("//ID").count();
you can also query the linq statement as order by using specific conditions
Inorder to get node value from a list u can use this
foreach (XmlNode xNode in xDoc.SelectNodes("//ListIDS/ListID"))
{
Console.WriteLine(xNode.InnerText);
}
For Second list you havnt got the value since, the XPath for list items is not correct