0
votes

This is my XML given:

<WorkItem>
    <Id>717</Id>
    <WorkItemType>Product Backlog Item</WorkItemType>
    <TreeLevel>1</TreeLevel>
    <Children>
        <WorkItem>
            <Id>719</Id>
            <WorkItemType>Product Backlog Item</WorkItemType>
            <TreeLevel>2</TreeLevel>
            <Children>
                <WorkItem>
                    <Id>721</Id>
                    <WorkItemType>Task</WorkItemType>
                    <TreeLevel>3</TreeLevel>
                    <Children>
                        <WorkItem>
                            <Id>722</Id>
                            <WorkItemType>Task</WorkItemType>
                            <TreeLevel>4</TreeLevel>
                            <Children />
                        </WorkItem>
                    </Children>
                </WorkItem>
            </Children>
        </WorkItem>
        <WorkItem>
            <Id>720</Id>
            <WorkItemType>Product Backlog Item</WorkItemType>
            <TreeLevel>2</TreeLevel>
            <Children>
                <WorkItem>
                    <Id>724</Id>
                    <WorkItemType>Task</WorkItemType>
                    <TreeLevel>3</TreeLevel>
                    <Children>
                        <WorkItem>
                            <Id>726</Id>
                            <WorkItemType>Task</WorkItemType>
                            <TreeLevel>4</TreeLevel>
                            <Children />
                        </WorkItem>
                    </Children>
                </WorkItem>
                <WorkItem>
                    <Id>725</Id>
                    <WorkItemType>Task</WorkItemType>
                    <TreeLevel>3</TreeLevel>
                    <Children>
                        <WorkItem>
                            <Id>727</Id>
                            <WorkItemType>Task</WorkItemType>
                            <TreeLevel>4</TreeLevel>
                            <Children />
                        </WorkItem>
                        <WorkItem>
                            <Id>728</Id>
                            <WorkItemType>Task</WorkItemType>
                            <TreeLevel>4</TreeLevel>
                            <Children />
                        </WorkItem>
                        <WorkItem>
                            <Id>729</Id>
                            <WorkItemType>Task</WorkItemType>
                            <TreeLevel>4</TreeLevel>
                            <Children>
                                <WorkItem>
                                    <Id>745</Id>
                                    <WorkItemType>Task</WorkItemType>
                                    <TreeLevel>5</TreeLevel>
                                    <Children />
                                </WorkItem>
                                <WorkItem>
                                    <Id>746</Id>
                                    <WorkItemType>Task</WorkItemType>
                                    <TreeLevel>5</TreeLevel>
                                    <Children />
                                </WorkItem>
                            </Children>
                        </WorkItem>
                    </Children>
                </WorkItem>
            </Children>
        </WorkItem>
        <WorkItem>
            <Id>723</Id>
            <WorkItemType>Task</WorkItemType>
            <TreeLevel>2</TreeLevel>
            <Children>
                <WorkItem>
                    <Id>744</Id>
                    <WorkItemType>Task</WorkItemType>
                    <TreeLevel>3</TreeLevel>
                    <Children />
                </WorkItem>
            </Children>
        </WorkItem>
    </Children>
</WorkItem>

I would like to retrieve all nodes of a node with subnodes two a certain types. If this type is of one kind I would like to get all descendant as well.

I tried to receive it with this xpath command (I use System.Xml.XmlDocument in C#):

xmlDoc.SelectNodes("Children/WorkItem[WorkItemType[text()='Product Backlog Item']]|Children/WorkItem[WorkItemType[text()='Task']]/following::WorkItem[WorkItemType[text()='Task']]");

// splitted for better readability
Children/WorkItem[
    WorkItemType[
        text()='Product Backlog Item']
    ]|
    Children/WorkItem[
        WorkItemType[
           text()='Task']
    ]/following::WorkItem[WorkItemType[text()='Task']]

This provides me only the nodes with ID 719 and 720. But I expect the WorkItem nodes with Id's: 719 and 720 (first part of the xpath expression) as well as 723 and 744 (from the second xpath expression).

  • My goal is to have WorkItem-elements of WorkItemType 'Product Backlog Item' which has Children WorkItem-Elements of WorkItemType 'Product Backlog Item' as well as 'Task'.
    • In case of a WorkItem-element of type 'Task' I want to have all child WorkItem-elements below.

How can I express this in XPath?

In the given XML I expect the WorkItem-elements with ID's 719,720,723,744

2
The XPath expression will help you to select the element (Children) based on the condition you defined in it, but it will not filter some elements out in the selected elements - you should do it manually. Why do you want to select the Workitem 744, but not the WorkItem 746? Your filter options are not clear for me.Sergii Zhevzhyk
I think you need to select the Task WorkItem separately to it's children like this: Children/WorkItem[WorkItemType[text()='Product Backlog Item']]|Children/WorkItem[WorkItemType[text()='Task']]|Children/WorkItem[WorkItemType[text()='Task']]/Children/WorkItemKeith Hall
@SergiiZhevzhyk Thank you for your reply. I want to filter Product Backlog Items with direct child Product Backlog Items and Tasks. Additionally I want to know all Sub-Tasks of the tasks. 746 is no direct child of 717 but 723 is.Bruno Bieri
@KeithHall I need to get all decendants. At design time it's not clear how deep the nesting will be (the given example has only 2) but in actual scenario I could have 3,7,10 it's not clear.Bruno Bieri
I think I found the xpath expression which works for me Children/WorkItem[WorkItemType[text()='Product Backlog Item']]|Children/WorkItem[WorkItemType[text()='Task']]/descendant-or-self::WorkItem[WorkItemType[text()='Task']]Bruno Bieri

2 Answers

0
votes

It's still unclear what you want to achieve but I will try to show you a possible solution to handle this task.

In my opinion it doesn't make sence to create a giant XPath expression, because it can be really hard to understand after some years. For your case it's impossible to get everything you want in one XPath expression. You could split it up:

foreach (var element in xmlDoc.SelectNodes("WorkItem/Children").OfType<XmlElement>())
{
    var elements = element.SelectNodes("WorkItem[WorkItemType[text()='Product Backlog Item' or text()='Task']]");
    foreach(var child in elements.OfType<XmlElement>())
         Process(child);                
}

public void Process(XmlElement rootElement)
{
    // Print some info about the work item
    // ...

    foreach (var element in rootElement.SelectNodes("Children").OfType<XmlElement>())
    {
        // I'm not sure whether it's exactly what you want but you can 
        // easily change this expression.
        var children = element.SelectNodes("WorkItem[WorkItemType[text()='Task']]");

        // continue the processing of children
        foreach (var child in children.OfType<XmlElement>())
            Process(child);
    }
}

First, you check all nodes of the WorkItems of the root children and then send them to the Process method which is also called inside (recursion). It will help you to process even deeper hierarchical structures.

0
votes

I found a xpath which works for what I want to do:

Children/WorkItem[WorkItemType[text()='Product Backlog Item']]|Children/WorkItem[WorkItemType[text()='Task']]/descendant-or-self::WorkI‌​tem[WorkItemType[text()='Task']]

for better readability

Children/WorkItem[WorkItemType[
                  text()='Product Backlog Item']
                 ]|
         Children/WorkItem[WorkItemType[
                           text()='Task']
                          ]/descendant-or-self::WorkI‌​tem[WorkItemType[
                                                         text()='Task']]