How to Mask or Replace the values in XML? - c#

I have this XML:
<?xml version="1.0" encoding="UTF-8"?>
<TXLife xmlns="http://ACORD.org/Standards/Life/2" Version="2.22.00">
<TXLifeRequest>
<OLifE Version="2.22.0">
<Party id="BEB7-BDDC43FE3F01_10004">
<PartyTypeCode tc="1">PT_PERSON</PartyTypeCode>
<FullName>Gump,Forrest</FullName>
<ResidenceState tc="58">USA_WI</ResidenceState>
<Person id="D7329BB530E8_10304">
<FirstName>Forrest</FirstName>
<LastName>Gump</LastName>
</Person>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
I want Replace the FirstName value to No Name.
This is related to Data Masking.
I'm trying to access the node with the given code below, but it is not working.
var testXML = XDocument.Load("C:\\DataMask\\P0500015703691806181259345440127.xml");
var nodePTCode = testXML.Descendants("Party").FirstOrDefault(cd => cd.Element("PartyTypeCode").Value == "PT_PERSON");

The namespace has to be included when addressing the elements.
Also for an XDocument you have to start from its Root property.
XDocument xdoc = XDocument.Load("C:\\DataMask\\P0500015703691806181259345440127.xml");
XNamespace ns = "http://ACORD.org/Standards/Life/2";
XElement firstName = xdoc.Root.Descendants(ns + "FirstName").FirstOrDefault();
if (firstName != null) { firstName.Value = "No Name"; }
The xml will have the update applied:
<TXLife xmlns="http://ACORD.org/Standards/Life/2" Version="2.22.00">
<TXLifeRequest>
<OLifE Version="2.22.0">
<Party id="BEB7-BDDC43FE3F01_10004">
<PartyTypeCode tc="1">PT_PERSON</PartyTypeCode>
<FullName>Gump,Forrest</FullName>
<ResidenceState tc="58">USA_WI</ResidenceState>
<Person id="D7329BB530E8_10304">
<FirstName>No Name</FirstName>
<LastName>Gump</LastName>
</Person>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
Edit
If applicable, you'll also have to update the FullName xml element to reflect the change in FirstName.
XElement lastName = xdoc.Root.Descendants(ns + "LastName").FirstOrDefault();
XElement fullName = xdoc.Root.Descendants(ns + "FullName").FirstOrDefault();
fullName.Value = String.Format("{0},{1}", (String)lastName, (String)firstName);

Related

XElement with LINQ Select and optional elements

I am trying to display some date from some XML I get from an external service. I am using XElement and I try to use LINQ select to get my data.
var xElem = XElement.Load(HttpUtility.UrlPathEncode(url));
var books = (from pubs in xElem.Elements("result")
select new
{
Id = (string)pubs.Element("data").Element("id"),
Title = (string)pubs.Element("data").Element("title"),
Year = (string)pubs.Element("data").Element("year"),
Resources = (string)pubs.Element("data")
.Element("resource")
.Element("url")
.ElementValueNull(),
Authors= pubs.Element("data").Elements("person")
}).ToList();
foreach (var book in books)
{
// Put the string together with string builder....
foreach (var person in book.Authors)
{
//Get the authors
}
}
And of course I have made the class for ElementValueNull.
//This method is to handle if element is missing
public static string ElementValueNull(this XElement element)
{
if (element != null)
return element.Value;
return "";
}
//This method is to handle if attribute is missing
public static string AttributeValueNull(this XElement element, string attributeName)
{
if (element == null)
return "";
else
{
XAttribute attr = element.Attribute(attributeName);
return attr == null ? "" : attr.Value;
}
}
The problem is that the resource tag with it's elements are not always present. And if it isn't there it will skip the whole record. Is there any easy way of making it so that it will just make the Resources have the empty string returned from my class but still add the record still using a LINQ select?
EDIT with XML example:
<?xml version="1.0" encoding="UTF-8"?>
<tester xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://tester.no/xmlSchema/xsd/tester.xsd">
<generert>2014-12-01</generert>
<result>
<data>
<id>297474</id>
<person>
<id>11690</id>
<surname>Medel-Svensson</surname>
<firstname>Ronnie</firstname>
</person>
<title>Title 1</title>
<year>2009</year>
</data>
</result>
<result>
<data>
<id>807059</id>
<person>
<id>11690</id>
<surname>Bronskimlet</surname>
<firstname>Hallstein</firstname>
</person>
<person>
<id>328009</id>
<surname>Kroksleiven</surname>
<firstname>Jostein</firstname>
</person>
<person>
<id>328010</id>
<surname>Gassolini</surname>
<firstname>Ruffino</firstname>
</person>
<person>
<id>327990</id>
<surname>von Schnellfahrer</surname>
<firstname>Heinrich</firstname>
</person>
<title>Title 2</title>
<year>2010</year>
<resource>
<type>
<code>TEXT</code>
</type>
<url>http://www.example.com/</url>
</resource>
</data>
</result>
<result>
<data>
<id>1164653</id>
<person>
<id>11690</id>
<surname>Bergsprekken</surname>
<firstname>Mysil</firstname>
</person>
<title>Title 3</title>
<year>2014</year>
<resource>
<type>
<code>FULLTEKST</code>
</type>
<url>http://www.example.com/</url>
</resource>
</data>
</result>
</tester>
A couple of things:
if you use Element(..), then the result could be null. This may cause null reference exceptions if elements are missing in your path. A more elegant way to handle this would be to use sequences and return an element if present using SingleOrDefault()
Both XElement and XAttribute have a bunch of explicit type conversion operators built in. This means you can cast to string and various other primitives. As string is a reference type, it would return null if the XObject was null. Value types such as int would throw an exception in this case, though int? would not.
With this in mind, something like this should solve your problem. Note as 'data' is common to all, you can put this in the initial selector:
from pubs in xElem.Elements("result").Elements("data")
select new
{
Id = (string)pubs.Element("id"),
Title = (string)pubs.Element("title"),
Year = (string)pubs.Element("year"),
Resources = (string)pubs.Elements("resource")
.Elements("url")
.SingleOrDefault(),
Authors= pubs.Elements("person")
}

Get Element from XDocument & Edit Attribute

<GetPromotionByIdResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" MajorVersion="2" xmlns="http://fake.com/services">
<Header>
<Response ResponseCode="OK">
<RequestID>1</RequestID>
</Response>
</Header>
<Promotion PromotionId="5200" EffectiveDate="2014-10-10T00:00:00" ExpirationDate="2014-11-16T23:59:00" PromotionStatus="Active" PromotionTypeName="DefaultPromotion">
<Description TypeCode="Long" Culture="en-AU">Promotion Description</Description>
</Promotion>
</GetPromotionByIdResponse>
Im trying to extract this
<Promotion PromotionId="5200" EffectiveDate="2014-10-10T00:00:00" ExpirationDate="2014-11-16T23:59:00" PromotionStatus="Active" PromotionTypeName="DefaultPromotion">
<Description TypeCode="Long" Culture="en-AU">Promotion Description</Description>
</Promotion>
and convert the PromotionId="5200" to PromotionId="XXX"
I can extract the < Promotion > element with the below code but cant work out how to change the attribute
XNamespace xmlResponseNamespace = xmlPromotionResponse.Root.GetDefaultNamespace();
XmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable());
nsm.AddNamespace("def", xmlResponseNamespace.ToString());
XElement xmlPromotionElement =
xmlPromotionResponse
.Descendants().SingleOrDefault(p => p.Name.LocalName == "Promotion");
You can try this way :
XNamespace ns = "http://fake.com/services";
XElement xmlPromotionElement = xmlPromotionResponse.Descendants(ns+"Promotion")
.SingleOrDefault();
xmlPromotionElement.Attribute("PromotionId").Value = "XXX";
Use simple XNamespace + local-name to reference an element in namespace. Then you can use .Attribute() method to get XAttribute from an XElement and change the attribute's value.
Try this : It returns the value of all attributes in Promotion Tag.
XNamespace ns1 = XNamespace.Get("http://fake.com/services");
var readPromotion = from a in xx.Descendants(ns1 + "Promotion")
select new
{
PromotionID = (string)a.Attribute("PromotionId"),
EffectiveDate = (string)a.Attribute("EffectiveDate"),
ExpirationDate = (string)a.Attribute("ExpirationDate"),
PromotionStatus = (string)a.Attribute("PromotionStatus"),
PromotionTypeName = (string)a.Attribute("PromotionTypeName"),
Description = (string)a.Value
};
foreach (var read in readPromotion)
{
// Read values
}

Variable in XPathSelectElement

I'm using XPathSelectElement to store data into an XML file. How can I in the code snippet below use a global variable name instead of id name 'City1'?
I want the code to be:
string myVariable = "City1"
XElement fname= country.XPathSelectElement("country/city/major[#id = myVariable]/firstname");
Thank you for your help
This is my XML:
<country>
<city>
<cityname>City1</cityname>
<citynr>111</citynr>
<person>
<name>Person1</name>
<name>Person2</name>
<name>Person3</name>
<name>Person4</name>
</person>
<major id=City1>
<firstname>Major1firstname</firstname>
<lastname>Major1lastname</lastname>
</major>
</city>
<city>
<cityname>City2</cityname>
<citynr>222</citynr>
<person>
<name>Person5</name>
<name>Person6</name>
<name>Person7</name>
<name>Person8</name>
</person>
<major id=City2>
<firstname>Major2firstname</firstname>
<lastname>Major2firstname</lastname>
</major>
</city>
</country>
Here is my code:
XDocument country= XDocument.Load(Server.MapPath("myXML.xml"));
XElement fname= country.XPathSelectElement("country/city/major[#id = 'City1']/firstname");
XElement lname= country.XPathSelectElement("country/city/major[#id = 'City1']/lastname");
fname.Value = firstname.Text;
lname.Value = lastname.Text;
country.Save(Server.MapPath("myXML.xml"));
I'd just use the selection methods within LINQ to XML instead:
XElement fname = country.Element("country")
.Elements("city")
.Elements("major")
.Where(x => (string) x.Attribute("id") == myVariable)
.Elements("firstname")
.FirstOrDefault();
(By using FirstOrDefault, the result will be null if no such element is found.)
You may use:
var fname = country
.XPathSelectElement(
"//country/city/major[#id = '" + myVariable + "']/firstname");
or
var fname = country
.XPathSelectElement(
String.Format("//country/city/major[#id = '{0}']/firstname", myVariable));
I believe that one way through which you might mitigate the XPath injection that #Tomalak mentions in the comment below is to use the XName type instead of string (exception handling left out of scope intently):
XName myVariable = "City1";
you are either looking for string.Format or the StringBuilder class.
fname= country.XPathSelectElement(string.Format("country/city/major[#id = '{0}']/firstname",myVariable));
references:
http://msdn.microsoft.com/de-de/library/fht0f5be(v=vs.85).aspx
http://msdn.microsoft.com/de-de/library/2839d5h5(v=vs.90).aspx

Count people by gender

I need some help with C# and XML.
I'm building a web application and need to present information about number of peope with gender Male in a specific department (How many men in Dep1).
This is my XML file:
<company>
<department>
<departmentname>Dep 1</departmentname>
<people>
<person>
<name>Sean</name>
<date>2013-10-10</date>
<gender>male</gender>
<age>40</age>
</person>
<person>
<name>John</name>
<date>2013-10-18</date>
<gender>male</gender>
<age>45</age>
</person>
<person>
<name>Linda</name>
<date>2013-09-10</date>
<gender>female</gender>
<age>42</age>
</person>
<person>
<name>Bob</name>
<date>2013-10-01</date>
<gender>male</gender>
<age>35</age>
</person>
</people>
</department>
<department>
<departmentname>Dep 2</departmentname>
<people>
<person>
<name>Art</name>
<date>2013-09-10</date>
<gender>male</gender>
<age>38</age>
</person>
<person>
<name>Christina</name>
<date>2013-10-20</date>
<gender>female</gender>
<age>45</age>
</person>
<person>
<name>Marie</name>
<date>2013-09-10</date>
<gender>female</gender>
<age>49</age>
</person>
</people>
</department>
</company>
My code (not finished and not working):
XElement company= XElement.Load(Server.MapPath("myXML.xml"));
XElement department= (from p in company.Elements("department")
where p.Element("departmentname").Value == 'Dep 1' && p.Element
("gender").Value == 'male'
select p).Count;
numberTextBox.Text = department.Element; //???How to write to textbox
var department = (from p in company.Elements("department")
where p.Element("departmentname").Value == "Dep 1" && p.Element
("gender").Value == "male"
select p).Count();
You're not retrieving an XElement, you're retrieving an int (which is what Count returns).
Using var will infer this for you.
And per my comment: kon -> gender.
Let's separate out some of the elements of the search to make it easier to follow:
XElement depName = company.Descendants("departmentname")
.Where(x => x.Value == "Dep 1")
.FirstOrDefault();
XElement[] men = depName.Parent.Descendants("gender")
.Where(x => x.Value == "male")
.Where(x => (int)x.Parent.Element("age") > 40)
.ToArray();
int count = men.Length;
depName.Parent is the department element. From that we get all the gender's with the value male. So the variable men is only the genders. If you want the whole person element, use the men's Parent property to get that. For example:
foreach(XElement man in men)
Console.Writeline(man.Parent.Element("name").Value);
To assign to the textbox:
numberTextBox.Text = count.ToString(); // or men.Length.ToString()
Hope this will help you..
XmlDocument doc = new XmlDocument();
doc.Load(your document);
var items = doc.GetElementsByTagName("gender");
var x=items.Count;
int malecount=doc.SelectNodes("gender[. = \"male\"]").Count;
You could try just XMLDocument and Xpath, just use the following code
var xpath = "/company/department[departmentname='Dep 1']/people/person[/company/department/people/person/gender='male']/name";
var xmldoc = new XmlDocument();
xmldoc.Load("company.xml");
var result = xmldoc.SelectNodes(xpath);
if (result != null) Assert.AreEqual(4,result.Count);
Hope this helps.

Insert the data of richtextbox into existing xml in c# linq

I have a xml like this:
<?xml version="1.0" encoding="utf-8"?>
<assessment xmlns="http://xml.thinkcentral.com/pub/xml/hsp/assessment" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:tia="http://xml.thinkcentral.com/pub/xml/hsp/tia" xmlns:tibase="http://xml.thinkcentral.com/pub/xml/hsp/tibase" xsi:schemaLocation="http://xml.thinkcentral.com/pub/xml/hsp/assessment http://xml.thinkcentral.com/pub/xml1_2_6/hsp_assessment.xsd" isbn="9780547660455" buid="NA12_AG_G01CH01A" title="Chapter 1 Test Form A" num_questions="24" num_sections="1" type="Basal" intervenable="true" duration="P5Y" pausable="false" scramble="false">
<test_section id="1" name="Chapter 1 Test Form A" index="1">
<aaa testitem_id="NA12_AG_G01CH01A_01" template="hsp_testitem_mc1.xslt" id="1" bankable="true">
<tia:multipleChoiceTestItem total-points="1" questionType="Multiple Choice" sample="false" version_label="1.0">
<tia:directions>
<tia:tiDirectionLine>
<tia:textBody></tia:textBody>
</tia:tiDirectionLine>
<tia:address>Richtextbox Data</tia:address>
</tia:directions>
</tia:multipleChoiceTestItem>
</aaa>
<aaa testitem_id="NA12_AG_G01CH01A_02" template="hsp_testitem_mc1.xslt" id="2" bankable="true">
<tia:multipleChoiceTestItem total-points="1" questionType="Multiple Choice" sample="false" version_label="1.0">
<tia:directions>
<tia:tiDirectionLine>
<tia:textBody></tia:textBody>
</tia:tiDirectionLine>
<tia:address>Richtextbox Data</tia:address>
</tia:directions>
</tia:multipleChoiceTestItem>
</aaa>
</test_section>
</assessment>
I have to insert the the data according to the id of the aaa element.
<aaa testitem_id="NA12_AG_G01CH01A_01" template="hsp_testitem_mc1.xslt" id="1" bankable="true">
<aaa testitem_id="NA12_AG_G01CH01A_02" template="hsp_testitem_mc1.xslt" id="2"bankable="true">
if id="1" then data of ritchtextbox will be insert into tia:address node.
i am using the following code.
private void button2_Click(object sender, EventArgs e)
{
XDocument doc = XDocument.Load(#"d:\file.xml");
XNamespace ns = XNamespace.Get("http://tia.com");
var result= (from ele in doc.Descendants("aaa")
where ((string)ele.Attribute("id")) == "1"
select ele.Element(ns+"address")).FirstOrDefault();
if (result != null)
{
result.Value = richTextBox1.Text;
doc.Save(#"d:\file.xml");
}
MessageBox.Show("done");
}
its not working. how i do that?
First of al, the XML markup you have posted is not valid. I think the easiest way to read/write an XML document is Linq-XML. You have to import System.Xml.Linq namespace to use XDocument class and its method. Take a look at MSDN article.
XDocument doc = XDocument.Load(#"c:\file.xml");
var result = (from ele in doc.Descendants("aaa")
where ((string)ele.Attribute("id")) == "1"
select ele.Element("address")).FirstOrDefault();
if (result != null)
{
result.Value = richTextBox1.Text;
doc.Save(#"c:\file.xml");
}
XML document should be:
<?xml version="1.0" encoding="utf-8"?>
<root>
<aaa id="1">
<address>Hello World</address>
</aaa>
<aaa id="2">
<address>
write text of ritchtextbox here</address>
</aaa>
</root>
EDIT:
In OP, XML markup has some issues and I've fixes the markup (added namespace).
<?xml version="1.0" encoding="utf-8"?>
<aaa testitem_id="chapter1" template="hsp_testitem_mc1.xslt" id="1" bankable="true" xmlns:tia="http://tia.com">
<tia:multipleChoiceTestItem total-points="1" questionType="Multiple Choice" sample="false" version_label="1.0">
<tia:directions>
<tia:tiDirectionLine>
<tia:textBody />
</tia:tiDirectionLine>
<tia:address>I have to edited here.(Richtextbox data)</tia:address>
</tia:directions>
</tia:multipleChoiceTestItem>
</aaa>
Code to find <tia:address> and replace its value.
XDocument doc = XDocument.Load(file);
XNamespace ns = XNamespace.Get("http://tia.com");
var result = (from ele in doc.Descendants(ns + "address")
select ele).SingleOrDefault();
if (result != null)
{
result.Value = richTextBox1.Text;
doc.Save(file);
}
EDIT : After changes made by OP in opening post.
XDocument doc = XDocument.Load(file);
//Change the namespace
XNamespace ns = XNamespace.Get("http://xml.thinkcentral.com/pub/xml/hsp/tia");
var result = (
from ele in doc.Descendants(ns + "multipleChoiceTestItem")
where ele.Parent.Attribute("id").Value == "1"
select
ele.Descendants(ns+"address").FirstOrDefault()
).FirstOrDefault();
if (result != null)
{
result.Value = "World";
doc.Save(file);
}

Categories

Resources