2
\$\begingroup\$

I wrote this piece of code which works as expected:

XElement theContentWhichIncludeBuilds = xDocument.XPathSelectElement($"//Project/Group").Elements()
  .FirstOrDefault(e => e.Name== "Content" && e.Attribute("Included").Value == "buildings");

It targets all the Group elements under the Project nodes,
where its Content has an Include attribute with a value of buildings.

The base sample XML:

<Project>
  <Group>
    <Content Include="buildings"/>

I need to use the provided code on top in 2,3 places in my project, the problem with it is that some XML files that I will process will not have that structure, and I am checking if it has that elements based on the condition or not.

Obviously it may cause errors when it doesn't have that element or the needed architecture. So I need to put it in Try/Catch.

Isn't it better to check each level one-by one and if that existed then check for the next node? (That way also avoid using try/catch) Does anyone confirm the used method can be good or bad on this case, or can provide any better alternative method for it?

Edit:

The XML files could be similar to the .CSProj structure which I altered a bit for my need. basically, here we may have:

<Project>
Basic data under the project node, which might be the same in all documents
</Project>

only some may have:

  <Group>
    <Content Include="buildings"/>

Now we want to check if it doesn't have the missed part we be able to add it, or if it contained the part we may alter its' values.

It is an upgrade process of those documents.

\$\endgroup\$
5
  • \$\begingroup\$ Have you considered to Descendants("xyz").Any() to check element's existence? \$\endgroup\$ Jul 15, 2020 at 9:17
  • \$\begingroup\$ No didn't try, what is different, I am kind of new to XML iteration, found that there could be tons of ways for doing anything, at first liked the approach I used, cause it was just a single line, but now I am trying to consider other approaches and ideas, if you think it may has some benefits over my provided code, please provide your suggestion as some piece of code and tell me what differs here. Thanks. \$\endgroup\$
    – Kasrak
    Jul 15, 2020 at 9:21
  • \$\begingroup\$ Guess your approach may not cause the NullException if I am right. How can I change this code to your suggested approach? \$\endgroup\$
    – Kasrak
    Jul 15, 2020 at 9:23
  • \$\begingroup\$ No it will cause any exception. The Descendants, Elements and Attributes methods return those items where the predicate is met. If there is no match, then it will return an empty collection. The Any extension method checks the length of the collection. If it is zero then it returns false otherwise true. \$\endgroup\$ Jul 15, 2020 at 9:35
  • \$\begingroup\$ That's probably a fine way. If possible, could you provide that piece of code as an answer, so I be able to mark it as the answer. \$\endgroup\$
    – Kasrak
    Jul 15, 2020 at 9:36

1 Answer 1

2
\$\begingroup\$

There are several ways how you can process an XML using Linq2XML.

As I can understand you want to process only those XML files that are matching a given format. You can check this with XML native tools, like XSD or DTD schema definitions and validation or manually via XLinq.

If you want to check that with XLinq I would suggest to use the following methods: Descendants, Elements and Attributes. Each returns those items where the predicate is met. If there is no match, then it will return an empty collection.

If you combine this logic with the Any extension method then you can turn your query operators into existence operators. If the queried collection's length is zero then it returns false otherwise true.


I would suggest to break your logic into two sub-functions:

  • Check whether or not the given xml meets the desired format
  • Process only that xml, which satisfies the preconditions

EDIT: To reflect new requirements

Check the presence of the Group element and act based on its existence:

var xml = "<Project><Group><Content Include = \"buildings\" /></Group></Project>";
var xDocument = XDocument.Parse(xml);
var project = xDocument.Root;
var isGroupExist = project.Elements("Group").Any();
if (!isGroupExist)
{
    var group = new XElement("Group") { ... };
    project.AddAfterSelf(group);
}
//Process it
\$\endgroup\$
12
  • \$\begingroup\$ The main format of all could be the same, the key is some may have those elements and some may have not, so I want to add those elements into them. I am eager to see 2,3 lines of code based on your approach which I be able to judge and replace mine, can you please provide your approach in a simple 2,3 lines of code? \$\endgroup\$
    – Kasrak
    Jul 15, 2020 at 9:58
  • 1
    \$\begingroup\$ The Group element and its children might not be there. \$\endgroup\$
    – Kasrak
    Jul 15, 2020 at 10:14
  • 1
    \$\begingroup\$ @Kasrak I've just updated the my answer. \$\endgroup\$ Jul 15, 2020 at 10:57
  • 1
    \$\begingroup\$ thanks for the participation on this issue and sharing your idea, I still need to play with the idea and some other codes I gathered about it, BTW will mark this as the answer. \$\endgroup\$
    – Kasrak
    Jul 15, 2020 at 11:55
  • 1
    \$\begingroup\$ And yes I am aware of Element and Elements, as you have seen my example was also based on Elements filtering. \$\endgroup\$
    – Kasrak
    Jul 15, 2020 at 11:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.