Home All Groups Group Topic Archive Search About

Using XPath Against A Node

Author
5 Dec 2006 10:54 PM
Derek Hart
I bring in an xml file into vb.net by using xmlDoc.LoadXml(XMLString) - I
run xpath statements against the xml file to grab data from it, so I use, as
an example, //Vehicles/Vehicles/@make to get the make of the car.  But then
I pass a specific node from xmlDoc into another function, not the whole
xmlDoc, just a node from it.  And if I run an xpath against it, I have to
use .// (has a period at the beginning) so it does not grab info from the
parent.  So I would have to use .//Vehicles/Vehicles/@make so it references
the current node. I would think that if I passed a node to a vb.net
function, I could simply use an xpath statement that would work off the
passed in node, and I could assume that the top part of that node was the
new parent.  Is there a way to pass a node like this?

Derek

Author
6 Dec 2006 5:30 AM
FishingScout
Derek,

I am not sure what you meant by: "and I could assume that the top part
of that node was the new parent."

Using "/" will search the document root node immediate descendants.
Using "./" will search the context node immediate descendants.
Using "// will search anywhere in the entire document.
Using ".//" will search anywhere in the context node descendants.
Similarly, you could use "descendant::".

If you know the absolute path of the data you are looking for, you can
simply skip the "//" or the "/".  For example, if "Price" were an
attribute of "Model", which is an immediate descendant of Vehicles, you
could query for the price of a model using "Model/@Price".  If you are
a high paid developer you could search for a specific model using
"Model[.='Cadillac']/@Price".  You don't need to use ".//Model/@Price"
or "descendant::Model/@Price".

I don't know if this was helpful but .... I don't drive a Cadillac.


Derek Hart wrote:
Show quoteHide quote
> I bring in an xml file into vb.net by using xmlDoc.LoadXml(XMLString) - I
> run xpath statements against the xml file to grab data from it, so I use, as
> an example, //Vehicles/Vehicles/@make to get the make of the car.  But then
> I pass a specific node from xmlDoc into another function, not the whole
> xmlDoc, just a node from it.  And if I run an xpath against it, I have to
> use .// (has a period at the beginning) so it does not grab info from the
> parent.  So I would have to use .//Vehicles/Vehicles/@make so it references
> the current node. I would think that if I passed a node to a vb.net
> function, I could simply use an xpath statement that would work off the
> passed in node, and I could assume that the top part of that node was the
> new parent.  Is there a way to pass a node like this?
>
> Derek
Author
6 Dec 2006 5:20 PM
Derek Hart
So if I pass a node to a function, can I treat the top-most element as the
top parent? That is my question.  Or is the entire xml document sent with
it.  I do not want it to be possible to look at the whole document in the
function.  I just want to pass in a specific node.  Is it possible?

Derek


Show quoteHide quote
"FishingScout" <fishingsc***@comcast.net> wrote in message
news:1165383052.131851.94120@n67g2000cwd.googlegroups.com...
> Derek,
>
> I am not sure what you meant by: "and I could assume that the top part
> of that node was the new parent."
>
> Using "/" will search the document root node immediate descendants.
> Using "./" will search the context node immediate descendants.
> Using "// will search anywhere in the entire document.
> Using ".//" will search anywhere in the context node descendants.
> Similarly, you could use "descendant::".
>
> If you know the absolute path of the data you are looking for, you can
> simply skip the "//" or the "/".  For example, if "Price" were an
> attribute of "Model", which is an immediate descendant of Vehicles, you
> could query for the price of a model using "Model/@Price".  If you are
> a high paid developer you could search for a specific model using
> "Model[.='Cadillac']/@Price".  You don't need to use ".//Model/@Price"
> or "descendant::Model/@Price".
>
> I don't know if this was helpful but .... I don't drive a Cadillac.
>
>
> Derek Hart wrote:
>> I bring in an xml file into vb.net by using xmlDoc.LoadXml(XMLString) - I
>> run xpath statements against the xml file to grab data from it, so I use,
>> as
>> an example, //Vehicles/Vehicles/@make to get the make of the car.  But
>> then
>> I pass a specific node from xmlDoc into another function, not the whole
>> xmlDoc, just a node from it.  And if I run an xpath against it, I have to
>> use .// (has a period at the beginning) so it does not grab info from the
>> parent.  So I would have to use .//Vehicles/Vehicles/@make so it
>> references
>> the current node. I would think that if I passed a node to a vb.net
>> function, I could simply use an xpath statement that would work off the
>> passed in node, and I could assume that the top part of that node was the
>> new parent.  Is there a way to pass a node like this?
>>
>> Derek
>
Author
6 Dec 2006 5:53 PM
Martin Honnen
Derek Hart wrote:
> So if I pass a node to a function, can I treat the top-most element as the
> top parent? That is my question.  Or is the entire xml document sent with
> it.  I do not want it to be possible to look at the whole document in the
> function.  I just want to pass in a specific node.  Is it possible?

In the DOM an XmlNode always has an OwnerDocument property set to the
document that created the node. A node cannot exist without its owning
document as you can only create nodes with the factory methods of the
XmlDocument instance. A node does not need to have a ParentNode property
being non null however.

In terms of the XPath implementation with SelectSingleNode and
SelectNodes if the node is not inserted in the owning document then it
looks like the XPath / evaluates to the node itself. Thus if you do e.g.
   Dim Xml_Doc as XmlDocument = New XmlDocument()
   Dim SomeElement as XmlElement = Xml_Doc.CreateElement("whatever")
and pass that node around without inserting it into the document then
the node in terms of XPath and SelectNodes/SelectSingleNode does not
expose the document.


--

    Martin Honnen --- MVP XML
    http://JavaScript.FAQTs.com/
Author
6 Dec 2006 6:01 PM
FishingScout
If there is some reason you don't want a method to access the document
from a node, it is possible to create a new xml document with only that
node and its descendants and pass it to a method.  If the method
modifies the node you will need to do some work to replace the original
node with the modified node.

I don't know of any way to "protect" ancestor nodes within the DOM.

Derek Hart wrote:
Show quoteHide quote
> So if I pass a node to a function, can I treat the top-most element as the
> top parent? That is my question.  Or is the entire xml document sent with
> it.  I do not want it to be possible to look at the whole document in the
> function.  I just want to pass in a specific node.  Is it possible?
>
> Derek
>
>
> "FishingScout" <fishingsc***@comcast.net> wrote in message
> news:1165383052.131851.94120@n67g2000cwd.googlegroups.com...
> > Derek,
> >
> > I am not sure what you meant by: "and I could assume that the top part
> > of that node was the new parent."
> >
> > Using "/" will search the document root node immediate descendants.
> > Using "./" will search the context node immediate descendants.
> > Using "// will search anywhere in the entire document.
> > Using ".//" will search anywhere in the context node descendants.
> > Similarly, you could use "descendant::".
> >
> > If you know the absolute path of the data you are looking for, you can
> > simply skip the "//" or the "/".  For example, if "Price" were an
> > attribute of "Model", which is an immediate descendant of Vehicles, you
> > could query for the price of a model using "Model/@Price".  If you are
> > a high paid developer you could search for a specific model using
> > "Model[.='Cadillac']/@Price".  You don't need to use ".//Model/@Price"
> > or "descendant::Model/@Price".
> >
> > I don't know if this was helpful but .... I don't drive a Cadillac.
> >
> >
> > Derek Hart wrote:
> >> I bring in an xml file into vb.net by using xmlDoc.LoadXml(XMLString) - I
> >> run xpath statements against the xml file to grab data from it, so I use,
> >> as
> >> an example, //Vehicles/Vehicles/@make to get the make of the car.  But
> >> then
> >> I pass a specific node from xmlDoc into another function, not the whole
> >> xmlDoc, just a node from it.  And if I run an xpath against it, I have to
> >> use .// (has a period at the beginning) so it does not grab info from the
> >> parent.  So I would have to use .//Vehicles/Vehicles/@make so it
> >> references
> >> the current node. I would think that if I passed a node to a vb.net
> >> function, I could simply use an xpath statement that would work off the
> >> passed in node, and I could assume that the top part of that node was the
> >> new parent.  Is there a way to pass a node like this?
> >>
> >> Derek
> >
Author
7 Dec 2006 12:47 AM
Derek Hart
Any sample code on breaking the node off the original xml document into its
own "smaller" document and node?

Derek

Show quoteHide quote
"FishingScout" <fishingsc***@comcast.net> wrote in message
news:1165428062.794350.244660@n67g2000cwd.googlegroups.com...
> If there is some reason you don't want a method to access the document
> from a node, it is possible to create a new xml document with only that
> node and its descendants and pass it to a method.  If the method
> modifies the node you will need to do some work to replace the original
> node with the modified node.
>
> I don't know of any way to "protect" ancestor nodes within the DOM.
>
> Derek Hart wrote:
>> So if I pass a node to a function, can I treat the top-most element as
>> the
>> top parent? That is my question.  Or is the entire xml document sent with
>> it.  I do not want it to be possible to look at the whole document in the
>> function.  I just want to pass in a specific node.  Is it possible?
>>
>> Derek
>>
>>
>> "FishingScout" <fishingsc***@comcast.net> wrote in message
>> news:1165383052.131851.94120@n67g2000cwd.googlegroups.com...
>> > Derek,
>> >
>> > I am not sure what you meant by: "and I could assume that the top part
>> > of that node was the new parent."
>> >
>> > Using "/" will search the document root node immediate descendants.
>> > Using "./" will search the context node immediate descendants.
>> > Using "// will search anywhere in the entire document.
>> > Using ".//" will search anywhere in the context node descendants.
>> > Similarly, you could use "descendant::".
>> >
>> > If you know the absolute path of the data you are looking for, you can
>> > simply skip the "//" or the "/".  For example, if "Price" were an
>> > attribute of "Model", which is an immediate descendant of Vehicles, you
>> > could query for the price of a model using "Model/@Price".  If you are
>> > a high paid developer you could search for a specific model using
>> > "Model[.='Cadillac']/@Price".  You don't need to use ".//Model/@Price"
>> > or "descendant::Model/@Price".
>> >
>> > I don't know if this was helpful but .... I don't drive a Cadillac.
>> >
>> >
>> > Derek Hart wrote:
>> >> I bring in an xml file into vb.net by using
>> >> xmlDoc.LoadXml(XMLString) - I
>> >> run xpath statements against the xml file to grab data from it, so I
>> >> use,
>> >> as
>> >> an example, //Vehicles/Vehicles/@make to get the make of the car.  But
>> >> then
>> >> I pass a specific node from xmlDoc into another function, not the
>> >> whole
>> >> xmlDoc, just a node from it.  And if I run an xpath against it, I have
>> >> to
>> >> use .// (has a period at the beginning) so it does not grab info from
>> >> the
>> >> parent.  So I would have to use .//Vehicles/Vehicles/@make so it
>> >> references
>> >> the current node. I would think that if I passed a node to a vb.net
>> >> function, I could simply use an xpath statement that would work off
>> >> the
>> >> passed in node, and I could assume that the top part of that node was
>> >> the
>> >> new parent.  Is there a way to pass a node like this?
>> >>
>> >> Derek
>> >
>
Author
7 Dec 2006 4:55 AM
FishingScout
Derek,

Here is an example.  You will need to create a directory
"c:\xmlexample" or modify the paths in the code.  After the code below
is the contents of an xml file that you should name "dealership.xml"
and save to the directory that you created.  Even though changes can be
made to the XML DOM passed into the DoSomeXmlProcessing, they are not
available in the orignal XML DOM unless you copy them back into the
original XML DOM.  You can verify this by commenting out the
....InnerXml = ...InnerXml line.

Create a VB.NET windows application.

Replace the contents of Form1.vb with this:

Imports System.Xml

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Button1.Click

        Dim WholeXmlDocument As New XmlDocument
        WholeXmlDocument.Load("c:\xmlexample\dealership.xml")

        ' assume, for this example, the user wants
        ' all Chevy models displayed

        Dim VehicleNode As XmlNode = _
        WholeXmlDocument.SelectSingleNode("//Vehicles[@Make='Chevy']")

        If Not VehicleNode Is Nothing Then

            ' Create a new document from the Vehicle
            ' node so the other developers cannot
            ' modify the actual dealership document

            Dim ChevyXmlDoc As New XmlDocument
            ChevyXmlDoc.AppendChild(ChevyXmlDoc.ImportNode( _
                                    VehicleNode.Clone(), True))

            Dim bDocumentModified As Boolean

            bDocumentModified = DoSomeXmlProcessing(ChevyXmlDoc)

            ' Changes to the ChevyXmlDocument will only
            ' appear in the WholeXmlDocument if you copy
            ' the modified node back into the WholeXmlDocument
            If bDocumentModified Then
                VehicleNode.InnerXml = ChevyXmlDoc.Clone().InnerXml
            End If

            WholeXmlDocument.Save("c:\xmlexample\modified.xml")

        End If

    End Sub

    Private Function DoSomeXmlProcessing(ByRef ModelXmlDocument _
    As XmlDocument) As Boolean

        Dim bDocumentWasModified As Boolean = False

        ' Uplander sales are down so give it a
        ' nice rebate
        Dim UplanderNode As XmlNode = _
        ModelXmlDocument.SelectSingleNode("//Model[.='Uplander']")

        If Not UplanderNode Is Nothing Then

            ' 5000 should boost sales!

            UplanderNode.Attributes("Rebate").InnerText = "5000"

            bDocumentWasModified = True

        End If

        Return bDocumentWasModified

    End Function
End Class


=========================
dealership.xml
=========================

<?xml version="1.0" encoding="utf-8"?>
<Dealership>
  <Vehicles>
    <Vehicles Make="Chevy">
      <Model Price="49,000" Rebate="5000">Corvet</Model>
      <Model Price="34,000" Rebate="2500">Tahoe</Model>
      <Model Price="21,000" Rebate="0">Uplander</Model>
    </Vehicles>
    <Vehicles Make="Bavarian Motor Works">
      <Model Price="85,000" Rebate="0">740i</Model>
      <Model Price="45,000" Rebate="0">530i</Model>
      <Model Price="35,000" Rebate="0">325i</Model>
    </Vehicles>
  </Vehicles>
</Dealership>



Derek Hart wrote:
Show quoteHide quote
> Any sample code on breaking the node off the original xml document into its
> own "smaller" document and node?
>
> Derek
>
> "FishingScout" <fishingsc***@comcast.net> wrote in message
> news:1165428062.794350.244660@n67g2000cwd.googlegroups.com...
> > If there is some reason you don't want a method to access the document
> > from a node, it is possible to create a new xml document with only that
> > node and its descendants and pass it to a method.  If the method
> > modifies the node you will need to do some work to replace the original
> > node with the modified node.
> >
> > I don't know of any way to "protect" ancestor nodes within the DOM.
> >
> > Derek Hart wrote:
> >> So if I pass a node to a function, can I treat the top-most element as
> >> the
> >> top parent? That is my question.  Or is the entire xml document sent with
> >> it.  I do not want it to be possible to look at the whole document in the
> >> function.  I just want to pass in a specific node.  Is it possible?
> >>
> >> Derek
> >>
> >>
> >> "FishingScout" <fishingsc***@comcast.net> wrote in message
> >> news:1165383052.131851.94120@n67g2000cwd.googlegroups.com...
> >> > Derek,
> >> >
> >> > I am not sure what you meant by: "and I could assume that the top part
> >> > of that node was the new parent."
> >> >
> >> > Using "/" will search the document root node immediate descendants.
> >> > Using "./" will search the context node immediate descendants.
> >> > Using "// will search anywhere in the entire document.
> >> > Using ".//" will search anywhere in the context node descendants.
> >> > Similarly, you could use "descendant::".
> >> >
> >> > If you know the absolute path of the data you are looking for, you can
> >> > simply skip the "//" or the "/".  For example, if "Price" were an
> >> > attribute of "Model", which is an immediate descendant of Vehicles, you
> >> > could query for the price of a model using "Model/@Price".  If you are
> >> > a high paid developer you could search for a specific model using
> >> > "Model[.='Cadillac']/@Price".  You don't need to use ".//Model/@Price"
> >> > or "descendant::Model/@Price".
> >> >
> >> > I don't know if this was helpful but .... I don't drive a Cadillac.
> >> >
> >> >
> >> > Derek Hart wrote:
> >> >> I bring in an xml file into vb.net by using
> >> >> xmlDoc.LoadXml(XMLString) - I
> >> >> run xpath statements against the xml file to grab data from it, so I
> >> >> use,
> >> >> as
> >> >> an example, //Vehicles/Vehicles/@make to get the make of the car.  But
> >> >> then
> >> >> I pass a specific node from xmlDoc into another function, not the
> >> >> whole
> >> >> xmlDoc, just a node from it.  And if I run an xpath against it, I have
> >> >> to
> >> >> use .// (has a period at the beginning) so it does not grab info from
> >> >> the
> >> >> parent.  So I would have to use .//Vehicles/Vehicles/@make so it
> >> >> references
> >> >> the current node. I would think that if I passed a node to a vb.net
> >> >> function, I could simply use an xpath statement that would work off
> >> >> the
> >> >> passed in node, and I could assume that the top part of that node was
> >> >> the
> >> >> new parent.  Is there a way to pass a node like this?
> >> >>
> >> >> Derek
> >> >
> >