Output SiteMapNodeCollection as an XML file?

K

Ken Cox [Microsoft MVP]

Could you clarify what you need to do? The SiteMapPath control reads from
web.sitemap which is already an XML file.

Ken
Microsoft MVP [ASP.NET]
 
J

JJ

I am constructing a Flash menu system that builds its content based on the web.sitemap file. How Flash does that here is of no importance - it just needs URL access to the XML sitemap file.
However, due to the built-in security, the server does not allow the '.sitemap' file to be accessed directly.

I am therefore writing a handler to allow access to the file. I could do this easily by reading in the physical file and outputting it.
But if I was to use roles, I did not want the Flash menu to have access to nodes which had roles which were more privileged than the current user.

I then came across 'security trimming', which if enabled, filters out the nodes that the user should see, but only when you use certain commands to access the web.sitemap nodes.
Reading the physical file was bypassing security trimming, and so I'd have had to hand code the roles filtering. I noticed that when I copied the current web.sitemap into a sitenodemapcollection it filtered out any nodes the user wasn't meant to see. This would save me having to come up with code to parse the web.sitemap file and do the filtering myself.

But, I am not sure how I output that collection in a form, presumably of:
Dim writer As XmlTextWriter = New XmlTextWriter(response.OutputStream, Encoding.UTF8)

Currently I am having to iterate through the web.sitemap file in the handler and manually check if there is a role string present and if currentuser.IsInRole(rolestring). But its messy and I want to use the built in security trimming.



I hope I haven't made that too confusing. I'm a bit new to asp.net,

JJ



Ken Cox said:
Could you clarify what you need to do? The SiteMapPath control reads from
web.sitemap which is already an XML file.

Ken
Microsoft MVP [ASP.NET]

JJ said:
How can I get a SiteMapNodeCollection to output as an XML file?
 
K

Ken Cox [Microsoft MVP]

Hi JJ,

Okay, I think I understand. Try the following code and see if it approaches
what you're after? You would need to point the Flash to the file
FlashSiteMap.ashx as if it were an XML file 'cause that's what it outputs.

Let us know?

Ken
Microsoft MVP [ASP.NET]
(e-mail address removed)


<%@ WebHandler Language="VB" Class="FlashSiteMap" %>
' FlashSiteMap.ashx
' by Ken Cox [MVP]
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
' Gets the sitemap nodes and renders them
' via a handler to XML
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"

Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("Flashnodes", "http://pp/schemas/flashmap")

' Add root node
AddUrl(SiteMap.RootNode)

' Add all other nodes
Dim nodes As SiteMapNodeCollection = _
SiteMap.RootNode.GetAllNodes()
For Each node As SiteMapNode In nodes
AddUrl(node)
Next

writer_xml.WriteEndElement()
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Private Sub AddUrl(ByVal node As SiteMapNode)
' Open url tag
writer_xml.WriteStartElement("siteMapNode")
' Write location
writer_xml.WriteStartElement("url")
writer_xml.WriteString(node.Url)
writer_xml.WriteEndElement()
' Write description
writer_xml.WriteStartElement("description")
writer_xml.WriteString(node.Description)
writer_xml.WriteEndElement()

writer_xml.WriteStartElement("title")
writer_xml.WriteString(node.Title)
writer_xml.WriteEndElement()
' Close tag
writer_xml.WriteEndElement()
End Sub


Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class


I am constructing a Flash menu system that builds its content based on the
web.sitemap file. How Flash does that here is of no importance - it just
needs URL access to the XML sitemap file.
However, due to the built-in security, the server does not allow the
'.sitemap' file to be accessed directly.

I am therefore writing a handler to allow access to the file. I could do
this easily by reading in the physical file and outputting it.
But if I was to use roles, I did not want the Flash menu to have access to
nodes which had roles which were more privileged than the current user.

I then came across 'security trimming', which if enabled, filters out the
nodes that the user should see, but only when you use certain commands to
access the web.sitemap nodes.
Reading the physical file was bypassing security trimming, and so I'd have
had to hand code the roles filtering. I noticed that when I copied the
current web.sitemap into a sitenodemapcollection it filtered out any nodes
the user wasn't meant to see. This would save me having to come up with code
to parse the web.sitemap file and do the filtering myself.

But, I am not sure how I output that collection in a form, presumably of:
Dim writer As XmlTextWriter = New XmlTextWriter(response.OutputStream,
Encoding.UTF8)

Currently I am having to iterate through the web.sitemap file in the handler
and manually check if there is a role string present and if
currentuser.IsInRole(rolestring). But its messy and I want to use the built
in security trimming.



I hope I haven't made that too confusing. I'm a bit new to asp.net,

JJ



Could you clarify what you need to do? The SiteMapPath control reads from
web.sitemap which is already an XML file.

Ken
Microsoft MVP [ASP.NET]

JJ said:
How can I get a SiteMapNodeCollection to output as an XML file?
 
J

JJ

Ken,

Thanks - Thats _nearly_ what I want. It outputs all the nodes on one level
however, and splits up the attributes.
**Basically I need a way of making an identical copy of the sitemap, without
refering to the physcial file, or I'll bypass the security trimming.**

Do you lose the heirachical structure when you copy the sitemap to a
SiteMapNodeCollection?
If so I am on the wrong track completely.
Also, I need to allow for any custom attributes, like 'imageurl' for
example, so in my current code I use
writer.WriteAttributes(Reader, False) - but I guess as soon as you use an
XML reader it looks at the physical file and therefore bypasses security
trimming.
Would using some sort of Xpath structure do the trick? I did look at this,
but got confused...



JJ


Ken Cox said:
Hi JJ,

Okay, I think I understand. Try the following code and see if it
approaches what you're after? You would need to point the Flash to the
file FlashSiteMap.ashx as if it were an XML file 'cause that's what it
outputs.

Let us know?

Ken
Microsoft MVP [ASP.NET]
(e-mail address removed)


<%@ WebHandler Language="VB" Class="FlashSiteMap" %>
' FlashSiteMap.ashx
' by Ken Cox [MVP]
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
' Gets the sitemap nodes and renders them
' via a handler to XML
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"

Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("Flashnodes", "http://pp/schemas/flashmap")

' Add root node
AddUrl(SiteMap.RootNode)

' Add all other nodes
Dim nodes As SiteMapNodeCollection = _
SiteMap.RootNode.GetAllNodes()
For Each node As SiteMapNode In nodes
AddUrl(node)
Next

writer_xml.WriteEndElement()
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Private Sub AddUrl(ByVal node As SiteMapNode)
' Open url tag
writer_xml.WriteStartElement("siteMapNode")
' Write location
writer_xml.WriteStartElement("url")
writer_xml.WriteString(node.Url)
writer_xml.WriteEndElement()
' Write description
writer_xml.WriteStartElement("description")
writer_xml.WriteString(node.Description)
writer_xml.WriteEndElement()

writer_xml.WriteStartElement("title")
writer_xml.WriteString(node.Title)
writer_xml.WriteEndElement()
' Close tag
writer_xml.WriteEndElement()
End Sub


Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class


I am constructing a Flash menu system that builds its content based on the
web.sitemap file. How Flash does that here is of no importance - it just
needs URL access to the XML sitemap file.
However, due to the built-in security, the server does not allow the
'.sitemap' file to be accessed directly.

I am therefore writing a handler to allow access to the file. I could do
this easily by reading in the physical file and outputting it.
But if I was to use roles, I did not want the Flash menu to have access to
nodes which had roles which were more privileged than the current user.

I then came across 'security trimming', which if enabled, filters out the
nodes that the user should see, but only when you use certain commands to
access the web.sitemap nodes.
Reading the physical file was bypassing security trimming, and so I'd have
had to hand code the roles filtering. I noticed that when I copied the
current web.sitemap into a sitenodemapcollection it filtered out any nodes
the user wasn't meant to see. This would save me having to come up with
code to parse the web.sitemap file and do the filtering myself.

But, I am not sure how I output that collection in a form, presumably of:
Dim writer As XmlTextWriter = New XmlTextWriter(response.OutputStream,
Encoding.UTF8)

Currently I am having to iterate through the web.sitemap file in the
handler and manually check if there is a role string present and if
currentuser.IsInRole(rolestring). But its messy and I want to use the
built in security trimming.



I hope I haven't made that too confusing. I'm a bit new to asp.net,

JJ



Could you clarify what you need to do? The SiteMapPath control reads from
web.sitemap which is already an XML file.

Ken
Microsoft MVP [ASP.NET]

JJ said:
How can I get a SiteMapNodeCollection to output as an XML file?
 
K

Ken Cox [Microsoft MVP]

Hi JJ,

Here's a version that uses recursion to loop through all the child nodes
while maintaining the attributes.

It should reproduce the security trimming for the current user.

Let us know if this helps?

Ken
Microsoft MVP [ASP.NET]

<%@ webhandler class="FlashSiteMap" language="VB" %>
' FlashSiteMap.ashx
' Gets the sitemap nodes and renders them
' via a handler to XML
' Uses recursion to write the
' childnodes for a given node
' Ken Cox [MVP] ASP.NET
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"
Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
settings.NewLineHandling = NewLineHandling.Entitize
settings.NewLineOnAttributes = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("siteMap", "http://schemas.microsoft.com/AspNet/SiteMap-File-1.0")
'*******Recursive call here *******
RecurseSiteMapNode(SiteMap.RootNode.ChildNodes)
writer_xml.WriteEndElement()
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Sub RecurseSiteMapNode(ByVal nodes As SiteMapNodeCollection)
For Each newnode As SiteMapNode In nodes
writer_xml.WriteStartElement("siteMapNode")
writer_xml.WriteStartAttribute("url")
writer_xml.WriteString(newnode.Url)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("title")
writer_xml.WriteString(newnode.Title)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("description")
writer_xml.WriteString(newnode.Description)
writer_xml.WriteEndAttribute()
RecurseSiteMapNode(newnode.ChildNodes)
writer_xml.WriteEndElement()
Next
End Sub

Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class


JJ said:
Ken,

Thanks - Thats _nearly_ what I want. It outputs all the nodes on one level
however, and splits up the attributes.
**Basically I need a way of making an identical copy of the sitemap,
without refering to the physcial file, or I'll bypass the security
trimming.**

Do you lose the heirachical structure when you copy the sitemap to a
SiteMapNodeCollection?
If so I am on the wrong track completely.
Also, I need to allow for any custom attributes, like 'imageurl' for
example, so in my current code I use
writer.WriteAttributes(Reader, False) - but I guess as soon as you use an
XML reader it looks at the physical file and therefore bypasses security
trimming.
Would using some sort of Xpath structure do the trick? I did look at this,
but got confused...



JJ


Ken Cox said:
Hi JJ,

Okay, I think I understand. Try the following code and see if it
approaches what you're after? You would need to point the Flash to the
file FlashSiteMap.ashx as if it were an XML file 'cause that's what it
outputs.

Let us know?

Ken
Microsoft MVP [ASP.NET]
(e-mail address removed)


<%@ WebHandler Language="VB" Class="FlashSiteMap" %>
' FlashSiteMap.ashx
' by Ken Cox [MVP]
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
' Gets the sitemap nodes and renders them
' via a handler to XML
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"

Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("Flashnodes", "http://pp/schemas/flashmap")

' Add root node
AddUrl(SiteMap.RootNode)

' Add all other nodes
Dim nodes As SiteMapNodeCollection = _
SiteMap.RootNode.GetAllNodes()
For Each node As SiteMapNode In nodes
AddUrl(node)
Next

writer_xml.WriteEndElement()
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Private Sub AddUrl(ByVal node As SiteMapNode)
' Open url tag
writer_xml.WriteStartElement("siteMapNode")
' Write location
writer_xml.WriteStartElement("url")
writer_xml.WriteString(node.Url)
writer_xml.WriteEndElement()
' Write description
writer_xml.WriteStartElement("description")
writer_xml.WriteString(node.Description)
writer_xml.WriteEndElement()

writer_xml.WriteStartElement("title")
writer_xml.WriteString(node.Title)
writer_xml.WriteEndElement()
' Close tag
writer_xml.WriteEndElement()
End Sub


Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class


I am constructing a Flash menu system that builds its content based on
the web.sitemap file. How Flash does that here is of no importance - it
just needs URL access to the XML sitemap file.
However, due to the built-in security, the server does not allow the
'.sitemap' file to be accessed directly.

I am therefore writing a handler to allow access to the file. I could do
this easily by reading in the physical file and outputting it.
But if I was to use roles, I did not want the Flash menu to have access
to nodes which had roles which were more privileged than the current
user.

I then came across 'security trimming', which if enabled, filters out the
nodes that the user should see, but only when you use certain commands to
access the web.sitemap nodes.
Reading the physical file was bypassing security trimming, and so I'd
have had to hand code the roles filtering. I noticed that when I copied
the current web.sitemap into a sitenodemapcollection it filtered out any
nodes the user wasn't meant to see. This would save me having to come up
with code to parse the web.sitemap file and do the filtering myself.

But, I am not sure how I output that collection in a form, presumably
of:
Dim writer As XmlTextWriter = New XmlTextWriter(response.OutputStream,
Encoding.UTF8)

Currently I am having to iterate through the web.sitemap file in the
handler and manually check if there is a role string present and if
currentuser.IsInRole(rolestring). But its messy and I want to use the
built in security trimming.



I hope I haven't made that too confusing. I'm a bit new to asp.net,

JJ



Could you clarify what you need to do? The SiteMapPath control reads
from
web.sitemap which is already an XML file.

Ken
Microsoft MVP [ASP.NET]

How can I get a SiteMapNodeCollection to output as an XML file?
 
J

JJ

I'll give it a try now - any way of adding all attributes without having to
specifiy each one?
JJ

Ken Cox said:
Hi JJ,

Here's a version that uses recursion to loop through all the child nodes
while maintaining the attributes.

It should reproduce the security trimming for the current user.

Let us know if this helps?

Ken
Microsoft MVP [ASP.NET]

<%@ webhandler class="FlashSiteMap" language="VB" %>
' FlashSiteMap.ashx
' Gets the sitemap nodes and renders them
' via a handler to XML
' Uses recursion to write the
' childnodes for a given node
' Ken Cox [MVP] ASP.NET
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"
Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
settings.NewLineHandling = NewLineHandling.Entitize
settings.NewLineOnAttributes = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("siteMap", "http://schemas.microsoft.com/AspNet/SiteMap-File-1.0")
'*******Recursive call here *******
RecurseSiteMapNode(SiteMap.RootNode.ChildNodes)
writer_xml.WriteEndElement()
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Sub RecurseSiteMapNode(ByVal nodes As SiteMapNodeCollection)
For Each newnode As SiteMapNode In nodes
writer_xml.WriteStartElement("siteMapNode")
writer_xml.WriteStartAttribute("url")
writer_xml.WriteString(newnode.Url)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("title")
writer_xml.WriteString(newnode.Title)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("description")
writer_xml.WriteString(newnode.Description)
writer_xml.WriteEndAttribute()
RecurseSiteMapNode(newnode.ChildNodes)
writer_xml.WriteEndElement()
Next
End Sub

Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class


JJ said:
Ken,

Thanks - Thats _nearly_ what I want. It outputs all the nodes on one
level however, and splits up the attributes.
**Basically I need a way of making an identical copy of the sitemap,
without refering to the physcial file, or I'll bypass the security
trimming.**

Do you lose the heirachical structure when you copy the sitemap to a
SiteMapNodeCollection?
If so I am on the wrong track completely.
Also, I need to allow for any custom attributes, like 'imageurl' for
example, so in my current code I use
writer.WriteAttributes(Reader, False) - but I guess as soon as you use an
XML reader it looks at the physical file and therefore bypasses security
trimming.
Would using some sort of Xpath structure do the trick? I did look at
this, but got confused...



JJ


Ken Cox said:
Hi JJ,

Okay, I think I understand. Try the following code and see if it
approaches what you're after? You would need to point the Flash to the
file FlashSiteMap.ashx as if it were an XML file 'cause that's what it
outputs.

Let us know?

Ken
Microsoft MVP [ASP.NET]
(e-mail address removed)


<%@ WebHandler Language="VB" Class="FlashSiteMap" %>
' FlashSiteMap.ashx
' by Ken Cox [MVP]
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
' Gets the sitemap nodes and renders them
' via a handler to XML
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"

Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("Flashnodes", "http://pp/schemas/flashmap")

' Add root node
AddUrl(SiteMap.RootNode)

' Add all other nodes
Dim nodes As SiteMapNodeCollection = _
SiteMap.RootNode.GetAllNodes()
For Each node As SiteMapNode In nodes
AddUrl(node)
Next

writer_xml.WriteEndElement()
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Private Sub AddUrl(ByVal node As SiteMapNode)
' Open url tag
writer_xml.WriteStartElement("siteMapNode")
' Write location
writer_xml.WriteStartElement("url")
writer_xml.WriteString(node.Url)
writer_xml.WriteEndElement()
' Write description
writer_xml.WriteStartElement("description")
writer_xml.WriteString(node.Description)
writer_xml.WriteEndElement()

writer_xml.WriteStartElement("title")
writer_xml.WriteString(node.Title)
writer_xml.WriteEndElement()
' Close tag
writer_xml.WriteEndElement()
End Sub


Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class


I am constructing a Flash menu system that builds its content based on
the web.sitemap file. How Flash does that here is of no importance - it
just needs URL access to the XML sitemap file.
However, due to the built-in security, the server does not allow the
'.sitemap' file to be accessed directly.

I am therefore writing a handler to allow access to the file. I could
do this easily by reading in the physical file and outputting it.
But if I was to use roles, I did not want the Flash menu to have access
to nodes which had roles which were more privileged than the current
user.

I then came across 'security trimming', which if enabled, filters out
the nodes that the user should see, but only when you use certain
commands to access the web.sitemap nodes.
Reading the physical file was bypassing security trimming, and so I'd
have had to hand code the roles filtering. I noticed that when I copied
the current web.sitemap into a sitenodemapcollection it filtered out any
nodes the user wasn't meant to see. This would save me having to come up
with code to parse the web.sitemap file and do the filtering myself.

But, I am not sure how I output that collection in a form, presumably
of:
Dim writer As XmlTextWriter = New XmlTextWriter(response.OutputStream,
Encoding.UTF8)

Currently I am having to iterate through the web.sitemap file in the
handler and manually check if there is a role string present and if
currentuser.IsInRole(rolestring). But its messy and I want to use the
built in security trimming.



I hope I haven't made that too confusing. I'm a bit new to asp.net,

JJ



message
Could you clarify what you need to do? The SiteMapPath control reads
from
web.sitemap which is already an XML file.

Ken
Microsoft MVP [ASP.NET]

How can I get a SiteMapNodeCollection to output as an XML file?
 
J

JJ

It chops off the root node. I need that one as its displayed in the actual
web.sitemap.



Ken Cox said:
Hi JJ,

Here's a version that uses recursion to loop through all the child nodes
while maintaining the attributes.

It should reproduce the security trimming for the current user.

Let us know if this helps?

Ken
Microsoft MVP [ASP.NET]

<%@ webhandler class="FlashSiteMap" language="VB" %>
' FlashSiteMap.ashx
' Gets the sitemap nodes and renders them
' via a handler to XML
' Uses recursion to write the
' childnodes for a given node
' Ken Cox [MVP] ASP.NET
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"
Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
settings.NewLineHandling = NewLineHandling.Entitize
settings.NewLineOnAttributes = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("siteMap", "http://schemas.microsoft.com/AspNet/SiteMap-File-1.0")
'*******Recursive call here *******
RecurseSiteMapNode(SiteMap.RootNode.ChildNodes)
writer_xml.WriteEndElement()
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Sub RecurseSiteMapNode(ByVal nodes As SiteMapNodeCollection)
For Each newnode As SiteMapNode In nodes
writer_xml.WriteStartElement("siteMapNode")
writer_xml.WriteStartAttribute("url")
writer_xml.WriteString(newnode.Url)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("title")
writer_xml.WriteString(newnode.Title)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("description")
writer_xml.WriteString(newnode.Description)
writer_xml.WriteEndAttribute()
RecurseSiteMapNode(newnode.ChildNodes)
writer_xml.WriteEndElement()
Next
End Sub

Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class


JJ said:
Ken,

Thanks - Thats _nearly_ what I want. It outputs all the nodes on one
level however, and splits up the attributes.
**Basically I need a way of making an identical copy of the sitemap,
without refering to the physcial file, or I'll bypass the security
trimming.**

Do you lose the heirachical structure when you copy the sitemap to a
SiteMapNodeCollection?
If so I am on the wrong track completely.
Also, I need to allow for any custom attributes, like 'imageurl' for
example, so in my current code I use
writer.WriteAttributes(Reader, False) - but I guess as soon as you use an
XML reader it looks at the physical file and therefore bypasses security
trimming.
Would using some sort of Xpath structure do the trick? I did look at
this, but got confused...



JJ


Ken Cox said:
Hi JJ,

Okay, I think I understand. Try the following code and see if it
approaches what you're after? You would need to point the Flash to the
file FlashSiteMap.ashx as if it were an XML file 'cause that's what it
outputs.

Let us know?

Ken
Microsoft MVP [ASP.NET]
(e-mail address removed)


<%@ WebHandler Language="VB" Class="FlashSiteMap" %>
' FlashSiteMap.ashx
' by Ken Cox [MVP]
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
' Gets the sitemap nodes and renders them
' via a handler to XML
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"

Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("Flashnodes", "http://pp/schemas/flashmap")

' Add root node
AddUrl(SiteMap.RootNode)

' Add all other nodes
Dim nodes As SiteMapNodeCollection = _
SiteMap.RootNode.GetAllNodes()
For Each node As SiteMapNode In nodes
AddUrl(node)
Next

writer_xml.WriteEndElement()
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Private Sub AddUrl(ByVal node As SiteMapNode)
' Open url tag
writer_xml.WriteStartElement("siteMapNode")
' Write location
writer_xml.WriteStartElement("url")
writer_xml.WriteString(node.Url)
writer_xml.WriteEndElement()
' Write description
writer_xml.WriteStartElement("description")
writer_xml.WriteString(node.Description)
writer_xml.WriteEndElement()

writer_xml.WriteStartElement("title")
writer_xml.WriteString(node.Title)
writer_xml.WriteEndElement()
' Close tag
writer_xml.WriteEndElement()
End Sub


Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class


I am constructing a Flash menu system that builds its content based on
the web.sitemap file. How Flash does that here is of no importance - it
just needs URL access to the XML sitemap file.
However, due to the built-in security, the server does not allow the
'.sitemap' file to be accessed directly.

I am therefore writing a handler to allow access to the file. I could
do this easily by reading in the physical file and outputting it.
But if I was to use roles, I did not want the Flash menu to have access
to nodes which had roles which were more privileged than the current
user.

I then came across 'security trimming', which if enabled, filters out
the nodes that the user should see, but only when you use certain
commands to access the web.sitemap nodes.
Reading the physical file was bypassing security trimming, and so I'd
have had to hand code the roles filtering. I noticed that when I copied
the current web.sitemap into a sitenodemapcollection it filtered out any
nodes the user wasn't meant to see. This would save me having to come up
with code to parse the web.sitemap file and do the filtering myself.

But, I am not sure how I output that collection in a form, presumably
of:
Dim writer As XmlTextWriter = New XmlTextWriter(response.OutputStream,
Encoding.UTF8)

Currently I am having to iterate through the web.sitemap file in the
handler and manually check if there is a role string present and if
currentuser.IsInRole(rolestring). But its messy and I want to use the
built in security trimming.



I hope I haven't made that too confusing. I'm a bit new to asp.net,

JJ



message
Could you clarify what you need to do? The SiteMapPath control reads
from
web.sitemap which is already an XML file.

Ken
Microsoft MVP [ASP.NET]

How can I get a SiteMapNodeCollection to output as an XML file?
 
K

Ken Cox [Microsoft MVP]

Try this?

Ken
Microsoft MVP [ASP.NET]

<%@ webhandler class="FlashSiteMap" language="VB" %>
' FlashSiteMap.ashx
' Gets the root and sitemap nodes and renders them
' via a handler to XML
' Uses recursion to write the
' childnodes for a given node
' Ken Cox [MVP] ASP.NET
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"
Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
settings.NewLineHandling = NewLineHandling.Entitize
settings.NewLineOnAttributes = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("siteMap", "http://schemas.microsoft.com/AspNet/SiteMap-File-1.0")
' Write the root node
writer_xml.WriteStartElement("siteMapNode")
writer_xml.WriteStartAttribute("url")
writer_xml.WriteString(SiteMap.RootNode.Url)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("title")
writer_xml.WriteString(SiteMap.RootNode.Title)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("description")
writer_xml.WriteString(SiteMap.RootNode.Description)
writer_xml.WriteEndAttribute()
' Write the child nodes


'*******Recursive call here *******
RecurseSiteMapNode(SiteMap.RootNode.ChildNodes)
' Finish the root node
writer_xml.WriteEndElement()
' Finish the start of the childnodes
writer_xml.WriteEndElement()
' Finish the document
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Sub RecurseSiteMapNode(ByVal nodes As SiteMapNodeCollection)
For Each newnode As SiteMapNode In nodes
writer_xml.WriteStartElement("siteMapNode")
writer_xml.WriteStartAttribute("url")
writer_xml.WriteString(newnode.Url)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("title")
writer_xml.WriteString(newnode.Title)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("description")
writer_xml.WriteString(newnode.Description)
writer_xml.WriteEndAttribute()
RecurseSiteMapNode(newnode.ChildNodes)
writer_xml.WriteEndElement()
Next
End Sub

Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class
 
K

Ken Cox [Microsoft MVP]

I'm still looking at automating that. If you have custom attributes, it
looks like this is supported:

writer_xml.WriteString(newnode.Item("customattribute"))

Ken
Microsoft MVP [ASP.NET]
 
J

JJ

Ken that works, but I still am puzzled over how to get the unspecified
number of custom attributes.
I notice there is a SiteMapNode.Attributes Property - but it says its
'protected' and I can't figure out how I can use it?
JJ

Ken Cox said:
Try this?

Ken
Microsoft MVP [ASP.NET]

<%@ webhandler class="FlashSiteMap" language="VB" %>
' FlashSiteMap.ashx
' Gets the root and sitemap nodes and renders them
' via a handler to XML
' Uses recursion to write the
' childnodes for a given node
' Ken Cox [MVP] ASP.NET
' Adapted from Stephen Walther's code
' in ASP.NET 2.0 Unleashed, Chapter 18
Imports System
Imports System.Web
Imports System.Xml
Imports System.Text
Imports System.IO

Public Class FlashSiteMap
Implements IHttpHandler
Private writer_xml As XmlWriter

Public Sub ProcessRequest _
(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/xml"
Dim settings As New XmlWriterSettings()
settings.Encoding = Encoding.UTF8
settings.Indent = True
settings.NewLineHandling = NewLineHandling.Entitize
settings.NewLineOnAttributes = True
writer_xml = XmlWriter.Create _
(context.Response.OutputStream, settings)
writer_xml.WriteStartDocument()
writer_xml.WriteStartElement _
("siteMap", "http://schemas.microsoft.com/AspNet/SiteMap-File-1.0")
' Write the root node
writer_xml.WriteStartElement("siteMapNode")
writer_xml.WriteStartAttribute("url")
writer_xml.WriteString(SiteMap.RootNode.Url)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("title")
writer_xml.WriteString(SiteMap.RootNode.Title)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("description")
writer_xml.WriteString(SiteMap.RootNode.Description)
writer_xml.WriteEndAttribute()
' Write the child nodes


'*******Recursive call here *******
RecurseSiteMapNode(SiteMap.RootNode.ChildNodes)
' Finish the root node
writer_xml.WriteEndElement()
' Finish the start of the childnodes
writer_xml.WriteEndElement()
' Finish the document
writer_xml.WriteEndDocument()
writer_xml.Flush()
End Sub

Sub RecurseSiteMapNode(ByVal nodes As SiteMapNodeCollection)
For Each newnode As SiteMapNode In nodes
writer_xml.WriteStartElement("siteMapNode")
writer_xml.WriteStartAttribute("url")
writer_xml.WriteString(newnode.Url)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("title")
writer_xml.WriteString(newnode.Title)
writer_xml.WriteEndAttribute()
writer_xml.WriteStartAttribute("description")
writer_xml.WriteString(newnode.Description)
writer_xml.WriteEndAttribute()
RecurseSiteMapNode(newnode.ChildNodes)
writer_xml.WriteEndElement()
Next
End Sub

Public ReadOnly Property IsReusable() _
As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class


JJ said:
It chops off the root node. I need that one as its displayed in the
actual web.sitemap.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top