i am here to ask if there are any ways to put variables inside "#" Strings in C#.
Such that the id in the following code, can be changeable.
string xml = #"
<S>
<child id='1'/>
<child id='2'>
<grandchild id='3' />
<grandchild id='4' />
</child>
</S>";
take a look at the string.Format method
var result = string.Format(#"<S>
<child id='{0}'/>
<child id='{1}'>
<grandchild id='{2}' />
<grandchild id='{3}' />
</child>
</S>", id1, id2, id3, id4);
Not directly (C# doesn't have interpolation), but you can pass an #-string to string.Format or string.Concat. (or, for the masochasists, Regex.Replace)
You can use string.Format:
string.Format(#"<S>
<child id='{0}'/>
<child id='{1}'>
<grandchild id='3' />
<grandchild id='4' />
</child>
</S>", childId1, childId2);
Use string.Format() to insert values into your string at runtime. More info about it can be found on MSDN.
string xml = string.Format(#"
<S>
<child id='{0}'/>
<child id='{1}'>
<grandchild id='{2}' />
<grandchild id='{3}' />
</child>
</S>", id1, id2, id3, id4);
This isn't the recommended way to create XML though since you will have to make sure that any value you insert is properly escaped for it's location but as long as you are strictly inserting numerical values this shouldn't be a problem.
Related
I'm fairly new to LINQ but this seemed pretty straightforward.
I have an XML doc which contains a structure like this:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<folders>
<folder id="-1" parent="-100">
<name><![CDATA[Root]]></name>
<children>
<folder id="2" parent="-1">
<name><![CDATA[Contribution]]></name>
<documents />
<children>
<folder id="775" parent="2">
<name><![CDATA[category1]]></name>
<documents />
<children>
<folder id="2319" parent="775">
<name><![CDATA[Acad_Depts1]]></name>
<documents />
<children>
<folder id="26965" parent="2319">
<name><![CDATA[Student1]]></name>
<documents>
<document>
</document>
</documents>
</folder
</children>
</folder>
<folder id="2319" parent="775">
<name><![CDATA[Acad_Depts2]]></name>
<documents />
<children>
<folder id="26965" parent="2319">
<name><![CDATA[Student1]]></name>
<documents>
<document>
</document>
</documents>
</folder
</children>
</folder>
etc...
</children>
</folder>
</children>
</folder>
</children>
</folder>
</folders>
What I'm trying to do is to select all the elements with an attribute 'parent="775"'.
XElement xelement = XElement.Load("folders_only_registrar_folder.xml");
IEnumerable <XElement> folders = xelement.Elements();
var query = from node in folders.Descendants("folder")
where node.Attribute("parent").Value == registrarNodeID
select node;
Console.WriteLine(query.Count());
Console.ReadKey();
foreach(XElement departmentNode in query.Descendants("name"))
{
Console.WriteLine(departmentNode.Value.ToString());
}
When I run the query and test the count, I get 48 results (which is good)... but when I try to write out those same nodes, I get hundreds of results. For some reason it's giving me almost ALL of the elements named "folder" including children folders.
Thoughts as to what I'm doing wrong?
UPDATE... ok so now I know why i'm getting all the folders but any thoughts on how to create a collection of each grouping of nodes and sub-nodes?
Can the selection in LINQ send each 775 folder node (plus it's collective sub-nodes) into some sort of collection of nodes and then I could parse through them in a foreach by grouping of node?
Replace query.Descendants() with just query. query.Descendants() gets every child of every node that was originally contained within query.
I have an XElement which contains the content that I want. However, I want to add a namespace prefix to only the ref elements. Is this possible in C#?
For example, the original XML looks like this:
<Root>
<Element1 />
<Element2 />
<Element3>
<Element3_Child1 />
<Element3_Child2 />
</Element3>
<Element4 />
<Element5>
<Element5_Child1>
<Element5_Child1_Child51 />
</Element5_Child1>
</Element5>
</Root>
I want to add a namespace prefix, so that the XML looks as below
<Root>
<Element1 />
<Element2 />
<ns:Element3>
<Element3_Child1 />
<Element3_Child2 />
</Element3>
<Element4 />
<ns:Element5>
<ns:Element5_Child1>
<Element5_Child1_Child51 />
</Element5_Child1>
</Element5>
</Root>
You can do as stated here : http://www.w3schools.com/xml/xml_namespaces.asp
<root
xmlns:foo="http://www.example.org/foo"
xmlns:bar="http://www.example.org/bar">
However, I'm pretty sure you'll need a valid URI and that you can't "fake" one. Otherwise, the namespace will be invalid. But you can test and let us know.
I have an XElement, called "XUsers", that will contain XML which looks like this:
<users>
<user id="12345" name="Bob Smith" />
<user id="67890" name="Jamal Stevens" />
<user id="54321" name="Mary Jones" />
</users>
...and another XElement, called "XTasks", that will contain data like this:
<tasks>
<task id="1" title="Task 1" ownerId="54321" />
<task id="2" title="Task 2" ownerId="12345" />
<task id="3" title="Task 3" ownerId="67890" />
</tasks>
I want to add an attribute ("ownerName") to the task elements in the second XElement (XTasks), and set its values according to a "join" with the first XElement (XUsers). So, my final result will be that the XML in XTask will look like this:
<tasks>
<task id="1" title="Task 1" ownerId="54321" ownerName="Mary Jones" />
<task id="2" title="Task 2" ownerId="12345" ownerName="Bob Smith" />
<task id="3" title="Task 3" ownerId="67890" ownerName="Jamal Stevens" />
</tasks>
Is this possible using Linq? I haven't been able to find any examples of this sort of operation on the web. What is the most efficient way to accomplish this in my ASP.NET(C#) code?
Thanks for any advice you can give.
I am doing this without any IDE in front of me, so forgive me for any errors..
foreach (XElement task in XTasks.Elements())
{
XElement userNode = XUsers.Elements().Where(
e => e.Attribute("id").Value == task.Attribute("ownerId").Value).FirstOrDefault();
if (userNode != null)
{
task.Attribute("ownerName").SetValue(userNode.name);
}
}
The application I am developing receives an XML structure similar to following:
<Root>
<Valid>
<Child name="Child1" />
<Container>
<Child name="Child2" />
</Container>
<Container>
<Container>
<Child name="Child3"/>
<Child name="Child4"/>
</Container>
</Container>
<Wrapper>
<Child name="Child5" />
</Wrapper>
<Wrapper>
<Container>
<Child name="Child19" />
</Container>
</Wrapper>
<Container>
<Wrapper>
<Child name="Child6" />
</Wrapper>
</Container>
<Container>
<Wrapper>
<Container>
<Child name="Child20" />
</Container>
</Wrapper>
</Container>
</Valid>
<Invalid>
<Child name="Child7" />
<Container>
<Child name="Child8" />
</Container>
<Container>
<Container>
<Child name="Child9"/>
<Child name="Child10"/>
</Container>
</Container>
<Wrapper>
<Child name="Child11" />
</Wrapper>
<Container>
<Wrapper>
<Child name="Child12" />
</Wrapper>
</Container>
</Invalid>
</Root>
I need to get a list of of Child elements under following conditions:
Child is n generation descendant of Valid ancestor.
Child may be m generation descendant of Container ancestor which is o generation descendant of Valid ancestor.
Valid ancestors for Child element are Container elements as m generation ancestors and Valid element as first generation ancestor.
where m, n, o are natural numbers.
I need to write following XPath expressions
Valid/Child
Valid/Container/Child
Valid/Container/Container/Child
Valid/Container/Container/Container/Child
...
as a single XPath expression.
For provided example, the XPath expression would return only Child elements having name attribute equal to Child1, Child2, Child3 and Child4.
The closest I have come to solution is following expression.
Valid/Child | Valid//*[self::Container]/Child
However, this would select Child element with name attribute equal to Child19 and Child20.
Does XPath syntax supports either optional occurrence of an element or setting condition similar to self in previous example to all ancestors between Child and Valid elements?
Use:
//Child[ancestor::*
[not(self::Container)][1]
[self::Valid]
]
When this XPath expression is evaluated on the provided XML document:
<Root>
<Valid>
<Child name="Child1" />
<Container>
<Child name="Child2" />
</Container>
<Container>
<Container>
<Child name="Child3"/>
<Child name="Child4"/>
</Container>
</Container>
<Wrapper>
<Child name="Child5" />
</Wrapper>
<Wrapper>
<Container>
<Child name="Child19" />
</Container>
</Wrapper>
<Container>
<Wrapper>
<Child name="Child6" />
</Wrapper>
</Container>
<Container>
<Wrapper>
<Container>
<Child name="Child20" />
</Container>
</Wrapper>
</Container>
</Valid>
<Invalid>
<Child name="Child7" />
<Container>
<Child name="Child8" />
</Container>
<Container>
<Container>
<Child name="Child9"/>
<Child name="Child10"/>
</Container>
</Container>
<Wrapper>
<Child name="Child11" />
</Wrapper>
<Container>
<Wrapper>
<Child name="Child12" />
</Wrapper>
</Container>
</Invalid>
</Root>
Exactly the wanted nodes are selected:
<Child name="Child1"/>
<Child name="Child2"/>
<Child name="Child3"/>
<Child name="Child4"/>
Explanation:
The expression:
//Child[ancestor::*
[not(self::Container)][1]
[self::Valid]
]
means:
From all Child elements in the document, select only those, for which the first ancestor that is not a Container is Valid.
//Valid
//Child[count(ancestor::Container[ancestor::Valid])
= count(ancestor::*[ancestor::Valid])]
Explanation:
//Valid//Child
Returns all Child nodes that are descendants of Valid nodes.
count(ancestor::Container[ancestor::Valid]])
Returns the number of Container tags that are ancestors of the current node (Child) and themselves have an ancestor called Valid
count(ancestor::*[ancestor::Valid])
Returns the number of all tags that are ancestors of the current node (Child) and themselves have an ancestor called Valid
Therefore two values are only equal if all tags between Valid and Child are called Container.
However, this expression assumes that there won't be any nested Valid tags, i.e. /Valid/Valid/Child will not be accepted by it.
Update: Looking at your xml one more time, wouldn't this be easier?
//Valid//Child[not(ancestor::Wrapper)]
I've an xml file (Sample.xml) which has the following structure
<RootElement>
<Child Name="FirstChild" Start="1" End="2"/>
<Child Name="SecondChild" Start="0" End="2"/>
<Child Name="ThirdChild" Start="1" End="2"/>
<Child Name="FourthChild" Start="0" End="2"/>
<Child Name="FifthChild" Start="0" End="2"/>
<Child Name="SixthChild" Start="1" End="2"/>
<MatchedChilds>
<Child Name="FirstChild" />
<Child Name="SecondChild" />
<Child Name="ThirdChild" />
<Child Name="FourthChild" />
<Child Name="FifthChild" />
<Child Name="SixthChild" />
</MatchedChilds>
</RootElement>
i need to remove the elements "Child" if it is directly under "RootElement"
please give me a XML to LINQ approch to do this
You need to loop over the nodes and remove them, like this:
foreach(var child in root.Elements("Child").ToArray())
child.Remove();
The Elements call will return all direct child elements of the element you call it on; it will not return grandchildren;
You must call ToArray or you'll be modifying the collection as you enumerate it.
XDocument X_DOC = XDocument.Load(Application.StartupPath + "\\Sample.xml");
X_DOC.Root.Elements("Child").Remove();
X_DOC.Save(Application.StartupPath + "\\Sample.xml");