views:

32

answers:

1

I'm using C# and .NET 2.0.

Given the XML below, I'd like to get a XMLNodeList of <user> nodes where the <role> is "admin".

<users>
    <user>
        <name>John Doe</name>
        <roles>
            <role>superadmin</role>
            <role>admin</role>
        </roles>
    </user>
    <user>
        <name>Jane Doe</name>
        <roles>
            <role>superadmin</role>
            <role>admin</role>
        </roles>
    </user>
    <user>
        <name>Rob Doe</name>
        <roles>
            <role>support</role>
        </roles>
    </user>
 </users>

Assume roleName = "admin". This works, but is case-sensitive.

userNodesForRole = _document.SelectNodes("//users/user[roles[role='" + roleName + "']]");

I want to do it in a case-insensitive fashion. I know I can't use the matches function because .NET 2.0 (and maybe higher?) doesn't support XPath 2.0. So I did this:

// abc...xyz is the string literal of the entire alphabet, of course
userNodesForRole = _document.SelectNodes("//users/user[roles[translate(role,'abc..xyz','ABC...XYZ')='" + roleName.ToUpper() + "']]", _xmlNamespaceManager);

However, I don't get any nodes back. Can someone please tell me what I'm getting wrong?

+1  A: 

_document.SelectNodes("//users/user[roles[translate(role,'abc..xyz','ABC...XYZ')='" + roleName.ToUpper() + "']]", _xmlNamespaceManager);

This evaluates an XPath expression like the following:

  //users/user
           [roles
             [translate(role,
                        'abcdefghijklmnopqrstuvxyz',
                        'ABCDEFGHIJKLMNOPQRSTUVXYZ'
                        )
             =
              'ADMIN'
              ]
           ]

and the above XPath expression when evaluated on the provided XML document:

<users>
    <user>
        <name>John Doe</name>
        <roles>
            <role>admin</role>
        </roles>
    </user>
    <user>
        <name>Jane Doe</name>
        <roles>
            <role>admin</role>
        </roles>
    </user>
    <user>
        <name>Rob Doe</name>
        <roles>
            <role>support</role>
        </roles>
    </user>
 </users>

selects the following nodes:

<user>
    <name>John Doe</name>
    <roles>
        <role>admin</role>
    </roles>
</user>

<user>
    <name>Jane Doe</name>
    <roles>
        <role>admin</role>
    </roles>
</user>

The XPath expression will not select the wanted elements if there is a roles element that has more than one role child and a <role>admin</role> element is not the first role child of its parent.

An XPath expression that selects the desired elements even in this case is;

  //users/user
           [roles/role
             [translate(.,
                        'abcdefghijklmnopqrstuvxyz',
                        'ABCDEFGHIJKLMNOPQRSTUVXYZ'
                        )
             =
              'ADMIN'
              ]
           ]

There may be a variety of reasons why the first expression raises an exception or doesn't select the wanted nodes. To find out the exact reason, print the constructed XPath expression and provide it here.

Update: @ck has now provided his real XML document and indeed, in the real XML document the role children ( <role>admin</role> elements ) arenot the first role child of their parent.

So my guess and explanation was correct.

Dimitre Novatchev
Thank you. You hit the nail on the head. I've edited the question to reflect the actual XML I was trying to parse more closely.I do have a similar question, however. I'll post it separately.
ck
@ck: You are welcome.
Dimitre Novatchev