By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,035 Members | 1,064 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,035 IT Pros & Developers. It's quick & easy.

Remove a nodes where attribute has specified text. (Variable depth xml)

P: n/a
I have an XML document as follows:

<Menu>
<Group>
<Item Text="About Us" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="All" />
<Item Text="Option 3" AccessRoles="All" />
</Group>
</Item>
<Item Text="Projects" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="Employee" />
<Item Text="Option 3" AccessRoles="Manager,Executive" />
</Group>
</Item>
<Item Text="Library" AccessRoles="Employee,Manager,Executive">
<Group>
<Item Text="Option 1" AccessRoles="Employee" />
<Item Text="Option 2" AccessRoles="Manager" />
<Item Text="Option 3" AccessRoles="Executive" />
</Group>
</Item>
</Group>
</Menu>

This xml is used for telerik RADMenu component and before I use it with
the control I want to read the document and remove any menu options
(<Item>) that the current logged in user does not have roles for.

At the point of reading/parsing the document I have a comma-delimited
string (or ArrayList) of roles assigned to the current user (including
role "All") and so I need to check to see if any of the roles exist in
the AccessRoles attribute for each item.

The problem I am having is in removing the nodes that do not meet the
criteria.

I have been going down the following route (please note that this code
is only checking for the "All" role)...

Public Shared Function GetRoleBasedMenuXml() As String
Dim strMenuXml As String
Dim xmldocMenu As XmlDocument
strMenuXml = HttpContext.Current.Cache.Get("PortMenuXML")

xmldocMenu = New XmlDocument
xmldocMenu.LoadXml(strMenuXml)
Dim xmlnlMenuItem As XmlNodeList =
xmldocMenu.GetElementsByTagName("Item")

For Each xmlNode As XmlNode In xmlnlMenuItem
If Not xmlNode.Attributes("AccessRoles") Is Nothing Then
If xmlNode.Attributes("AccessRoles").Value <> "All" Then
xmlNode.RemoveAll()
xmlNode.RemoveChild(xmlNode.Parent)
End If
End If
Next

Dim swFormattedMenuXML As StringWriter
swFormattedMenuXML = New StringWriter
xmldocMenu.Save(swFormattedMenuXML)
Return swFormattedMenuXML.ToString()
End Function

The problem with this is that the RemoveAll() method only removes the
child nodes and the current node attributes leaving <Item></Item>. I
have tried to use xmlNode.ParentNode.RemoveChild(xmlNode) after the
RemoveAll but this is invalid in a For Each loop! I have spent most of
my day trying to find different ways around this problem (XPath etc.)
but because it is variable depth and also the nature of the AccessRoles
validation it has proved unfruitful - I am missing something!

Any help/suggestions would be greatly appreciated!

Nov 12 '05 #1
Share this Question
Share on Google+
8 Replies


P: n/a
This is a task that can be accomplished nicely with XSLT. Just override the
identity rule with an empty rule that matches the nodes to be removed.
Cheers,
Dimitre Novatchev.
"Mikey" <mi*****@sivers.co.uk> wrote in message
news:11**********************@g49g2000cwa.googlegr oups.com...
I have an XML document as follows:

<Menu>
<Group>
<Item Text="About Us" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="All" />
<Item Text="Option 3" AccessRoles="All" />
</Group>
</Item>
<Item Text="Projects" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="Employee" />
<Item Text="Option 3" AccessRoles="Manager,Executive" />
</Group>
</Item>
<Item Text="Library" AccessRoles="Employee,Manager,Executive">
<Group>
<Item Text="Option 1" AccessRoles="Employee" />
<Item Text="Option 2" AccessRoles="Manager" />
<Item Text="Option 3" AccessRoles="Executive" />
</Group>
</Item>
</Group>
</Menu>

This xml is used for telerik RADMenu component and before I use it with
the control I want to read the document and remove any menu options
(<Item>) that the current logged in user does not have roles for.

At the point of reading/parsing the document I have a comma-delimited
string (or ArrayList) of roles assigned to the current user (including
role "All") and so I need to check to see if any of the roles exist in
the AccessRoles attribute for each item.

The problem I am having is in removing the nodes that do not meet the
criteria.

I have been going down the following route (please note that this code
is only checking for the "All" role)...

Public Shared Function GetRoleBasedMenuXml() As String
Dim strMenuXml As String
Dim xmldocMenu As XmlDocument
strMenuXml = HttpContext.Current.Cache.Get("PortMenuXML")

xmldocMenu = New XmlDocument
xmldocMenu.LoadXml(strMenuXml)
Dim xmlnlMenuItem As XmlNodeList =
xmldocMenu.GetElementsByTagName("Item")

For Each xmlNode As XmlNode In xmlnlMenuItem
If Not xmlNode.Attributes("AccessRoles") Is Nothing Then
If xmlNode.Attributes("AccessRoles").Value <> "All" Then
xmlNode.RemoveAll()
xmlNode.RemoveChild(xmlNode.Parent)
End If
End If
Next

Dim swFormattedMenuXML As StringWriter
swFormattedMenuXML = New StringWriter
xmldocMenu.Save(swFormattedMenuXML)
Return swFormattedMenuXML.ToString()
End Function

The problem with this is that the RemoveAll() method only removes the
child nodes and the current node attributes leaving <Item></Item>. I
have tried to use xmlNode.ParentNode.RemoveChild(xmlNode) after the
RemoveAll but this is invalid in a For Each loop! I have spent most of
my day trying to find different ways around this problem (XPath etc.)
but because it is variable depth and also the nature of the AccessRoles
validation it has proved unfruitful - I am missing something!

Any help/suggestions would be greatly appreciated!

Nov 12 '05 #2

P: n/a
Reverse this call:
xmlNode.RemoveChild(xmlNode.Parent)

To become:
xmlNode.Parent.RemoveChild(xmlNode);

Then you don't even need:
xmlNode.RemoveAll()
"Mikey" <mi*****@sivers.co.uk> wrote in message
news:11**********************@g49g2000cwa.googlegr oups.com...
I have an XML document as follows:

<Menu>
<Group>
<Item Text="About Us" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="All" />
<Item Text="Option 3" AccessRoles="All" />
</Group>
</Item>
<Item Text="Projects" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="Employee" />
<Item Text="Option 3" AccessRoles="Manager,Executive" />
</Group>
</Item>
<Item Text="Library" AccessRoles="Employee,Manager,Executive">
<Group>
<Item Text="Option 1" AccessRoles="Employee" />
<Item Text="Option 2" AccessRoles="Manager" />
<Item Text="Option 3" AccessRoles="Executive" />
</Group>
</Item>
</Group>
</Menu>

This xml is used for telerik RADMenu component and before I use it with
the control I want to read the document and remove any menu options
(<Item>) that the current logged in user does not have roles for.

At the point of reading/parsing the document I have a comma-delimited
string (or ArrayList) of roles assigned to the current user (including
role "All") and so I need to check to see if any of the roles exist in
the AccessRoles attribute for each item.

The problem I am having is in removing the nodes that do not meet the
criteria.

I have been going down the following route (please note that this code
is only checking for the "All" role)...

Public Shared Function GetRoleBasedMenuXml() As String
Dim strMenuXml As String
Dim xmldocMenu As XmlDocument
strMenuXml = HttpContext.Current.Cache.Get("PortMenuXML")

xmldocMenu = New XmlDocument
xmldocMenu.LoadXml(strMenuXml)
Dim xmlnlMenuItem As XmlNodeList =
xmldocMenu.GetElementsByTagName("Item")

For Each xmlNode As XmlNode In xmlnlMenuItem
If Not xmlNode.Attributes("AccessRoles") Is Nothing Then
If xmlNode.Attributes("AccessRoles").Value <> "All" Then
xmlNode.RemoveAll()
xmlNode.RemoveChild(xmlNode.Parent)
End If
End If
Next

Dim swFormattedMenuXML As StringWriter
swFormattedMenuXML = New StringWriter
xmldocMenu.Save(swFormattedMenuXML)
Return swFormattedMenuXML.ToString()
End Function

The problem with this is that the RemoveAll() method only removes the
child nodes and the current node attributes leaving <Item></Item>. I
have tried to use xmlNode.ParentNode.RemoveChild(xmlNode) after the
RemoveAll but this is invalid in a For Each loop! I have spent most of
my day trying to find different ways around this problem (XPath etc.)
but because it is variable depth and also the nature of the AccessRoles
validation it has proved unfruitful - I am missing something!

Any help/suggestions would be greatly appreciated!

Nov 12 '05 #3

P: n/a
Sorry Chris, I have written this incorrectly! As you have suggested I
did use xmlNode.Parent.RemoveChild(xmlNode). But because this is in a
For Each loop this does not work?!

Chris Lovett wrote:
Reverse this call:
xmlNode.RemoveChild(xmlNode.Parent)

To become:
xmlNode.Parent.RemoveChild(xmlNode);

Then you don't even need:
xmlNode.RemoveAll()
"Mikey" <mi*****@sivers.co.uk> wrote in message
news:11**********************@g49g2000cwa.googlegr oups.com...
I have an XML document as follows:

<Menu>
<Group>
<Item Text="About Us" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="All" />
<Item Text="Option 3" AccessRoles="All" />
</Group>
</Item>
<Item Text="Projects" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="Employee" />
<Item Text="Option 3" AccessRoles="Manager,Executive" />
</Group>
</Item>
<Item Text="Library" AccessRoles="Employee,Manager,Executive">
<Group>
<Item Text="Option 1" AccessRoles="Employee" />
<Item Text="Option 2" AccessRoles="Manager" />
<Item Text="Option 3" AccessRoles="Executive" />
</Group>
</Item>
</Group>
</Menu>

This xml is used for telerik RADMenu component and before I use it with
the control I want to read the document and remove any menu options
(<Item>) that the current logged in user does not have roles for.

At the point of reading/parsing the document I have a comma-delimited
string (or ArrayList) of roles assigned to the current user (including
role "All") and so I need to check to see if any of the roles exist in
the AccessRoles attribute for each item.

The problem I am having is in removing the nodes that do not meet the
criteria.

I have been going down the following route (please note that this code
is only checking for the "All" role)...

Public Shared Function GetRoleBasedMenuXml() As String
Dim strMenuXml As String
Dim xmldocMenu As XmlDocument
strMenuXml = HttpContext.Current.Cache.Get("PortMenuXML")

xmldocMenu = New XmlDocument
xmldocMenu.LoadXml(strMenuXml)
Dim xmlnlMenuItem As XmlNodeList =
xmldocMenu.GetElementsByTagName("Item")

For Each xmlNode As XmlNode In xmlnlMenuItem
If Not xmlNode.Attributes("AccessRoles") Is Nothing Then
If xmlNode.Attributes("AccessRoles").Value <> "All" Then
xmlNode.RemoveAll()
xmlNode.RemoveChild(xmlNode.Parent)
End If
End If
Next

Dim swFormattedMenuXML As StringWriter
swFormattedMenuXML = New StringWriter
xmldocMenu.Save(swFormattedMenuXML)
Return swFormattedMenuXML.ToString()
End Function

The problem with this is that the RemoveAll() method only removes the
child nodes and the current node attributes leaving <Item></Item>. I
have tried to use xmlNode.ParentNode.RemoveChild(xmlNode) after the
RemoveAll but this is invalid in a For Each loop! I have spent most of
my day trying to find different ways around this problem (XPath etc.)
but because it is variable depth and also the nature of the AccessRoles
validation it has proved unfruitful - I am missing something!

Any help/suggestions would be greatly appreciated!


Nov 12 '05 #4

P: n/a
Sorry, there is a mistake in the vb code below...

xmlNode.RemoveChild(xmlNode.Parent) should have read
xmlNode.Parent.RemoveChild(xml*Node) which is in my working code.

I appologise for the diversion!

Mikey wrote:
I have an XML document as follows:

<Menu>
<Group>
<Item Text="About Us" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="All" />
<Item Text="Option 3" AccessRoles="All" />
</Group>
</Item>
<Item Text="Projects" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="Employee" />
<Item Text="Option 3" AccessRoles="Manager,Executive" />
</Group>
</Item>
<Item Text="Library" AccessRoles="Employee,Manager,Executive">
<Group>
<Item Text="Option 1" AccessRoles="Employee" />
<Item Text="Option 2" AccessRoles="Manager" />
<Item Text="Option 3" AccessRoles="Executive" />
</Group>
</Item>
</Group>
</Menu>

This xml is used for telerik RADMenu component and before I use it with
the control I want to read the document and remove any menu options
(<Item>) that the current logged in user does not have roles for.

At the point of reading/parsing the document I have a comma-delimited
string (or ArrayList) of roles assigned to the current user (including
role "All") and so I need to check to see if any of the roles exist in
the AccessRoles attribute for each item.

The problem I am having is in removing the nodes that do not meet the
criteria.

I have been going down the following route (please note that this code
is only checking for the "All" role)...

Public Shared Function GetRoleBasedMenuXml() As String
Dim strMenuXml As String
Dim xmldocMenu As XmlDocument
strMenuXml = HttpContext.Current.Cache.Get("PortMenuXML")

xmldocMenu = New XmlDocument
xmldocMenu.LoadXml(strMenuXml)
Dim xmlnlMenuItem As XmlNodeList =
xmldocMenu.GetElementsByTagName("Item")

For Each xmlNode As XmlNode In xmlnlMenuItem
If Not xmlNode.Attributes("AccessRoles") Is Nothing Then
If xmlNode.Attributes("AccessRoles").Value <> "All" Then
xmlNode.RemoveAll()
xmlNode.RemoveChild(xmlNode.Parent)
End If
End If
Next

Dim swFormattedMenuXML As StringWriter
swFormattedMenuXML = New StringWriter
xmldocMenu.Save(swFormattedMenuXML)
Return swFormattedMenuXML.ToString()
End Function

The problem with this is that the RemoveAll() method only removes the
child nodes and the current node attributes leaving <Item></Item>. I
have tried to use xmlNode.ParentNode.RemoveChild(xmlNode) after the
RemoveAll but this is invalid in a For Each loop! I have spent most of
my day trying to find different ways around this problem (XPath etc.)
but because it is variable depth and also the nature of the AccessRoles
validation it has proved unfruitful - I am missing something!

Any help/suggestions would be greatly appreciated!


Nov 12 '05 #5

P: n/a
Many thanks for the guidance Dimitre! Is there any chance of an
example? I have not used XSLT before and although I will start looking
at the documentation on msdn library an example for this scenario would
be a great help.
Thanks again!

Nov 12 '05 #6

P: n/a
Just a thought Mike,

instead of trying to delete the node from within the foreach loop which you
say doesn't work,
could you add each node that you want deleted into an ArrayList and then
after the foreach loop go through this Array and do the deleting that you
require?


"Mikey" <mi*****@sivers.co.uk> wrote in message
news:11*********************@f14g2000cwb.googlegro ups.com...
Sorry, there is a mistake in the vb code below...

xmlNode.RemoveChild(xmlNode.Parent) should have read
xmlNode.Parent.RemoveChild(xml*Node) which is in my working code.

I appologise for the diversion!

Nov 12 '05 #7

P: n/a
I have resolved the problem! - It amazing what a new day can do for
clearing the head! :) I just used a Do While Loop instead of the For
Each Loop.

Dim intIndex As Integer = 0
Dim intLimit As Integer = xmlnlMenuItem.Count - 1

Do While intIndex < intLimit
Dim node As XmlNode
node = xmlnlMenuItem.Item(intIndex)
If Not node.Attributes("AccessRoles") Is Nothing Then
If node.Attributes("AccessRoles").Value <> "All" Then
node.ParentNode.RemoveChild(node)
intIndex -= 1
intLimit = xmlnlMenuItem.Count - 1
End If
End If
intIndex += 1
Loop

Thankyou all for you help, I do appreciate it.

Nov 12 '05 #8

P: n/a

"Mikey" <mi*****@sivers.co.uk> wrote in message
news:11*********************@f14g2000cwb.googlegro ups.com...
Many thanks for the guidance Dimitre! Is there any chance of an
example? I have not used XSLT before and although I will start looking
at the documentation on msdn library an example for this scenario would
be a great help.
Thanks again!


Hi Mikey,

This transformation:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:user="user:roles"
exclude-result-prefixes="user">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<user:roles>
<role name="Employee"/>
</user:roles>

<xsl:variable name="vRoles"
select="document('')/*/user:roles/*"/>

<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>

<xsl:template match="Item">
<xsl:if test=
"$vRoles[contains(current()/@AccessRoles, @name)]
or
current()/@AccessRoles = 'All'">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

when applied on your source xml:

<Menu>
<Group>
<Item Text="About Us" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="All" />
<Item Text="Option 3" AccessRoles="All" />
</Group>
</Item>
<Item Text="Projects" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All" />
<Item Text="Option 2" AccessRoles="Employee" />
<Item Text="Option 3" AccessRoles="Manager,Executive" />
</Group>
</Item>
<Item Text="Library" AccessRoles="Employee,Manager,Executive">
<Group>
<Item Text="Option 1" AccessRoles="Employee" />
<Item Text="Option 2" AccessRoles="Manager" />
<Item Text="Option 3" AccessRoles="Executive" />
</Group>
</Item>
</Group>
</Menu>
produces the wanted result:

<Menu>
<Group>
<Item Text="About Us" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All">
</Item>
<Item Text="Option 2" AccessRoles="All">
</Item>
<Item Text="Option 3" AccessRoles="All">
</Item>
</Group>
</Item>
<Item Text="Projects" AccessRoles="All">
<Group>
<Item Text="Option 1" AccessRoles="All">
</Item>
<Item Text="Option 2" AccessRoles="Employee">
</Item>
</Group>
</Item>
<Item Text="Library" AccessRoles="Employee,Manager,Executive">
<Group>
<Item Text="Option 1" AccessRoles="Employee">
</Item>
</Group>
</Item>
</Group>
</Menu>

In the real case the user roles will not be embedded in the stylesheet, but
will be accessible as a separate xml document.
Cheers,
Dimitre Novatchev
Nov 12 '05 #9

This discussion thread is closed

Replies have been disabled for this discussion.