Logical Conjunctions

Introduction

Consider the following XML document from a file named Videos2.xml:

<?xml version="1.0" encoding="utf-8" ?>
<videos>
    <video>
        <title>The War of the Roses</title>
        <director>Danny DeVito</director>
        <actor>Michael Douglas</actor>
        <actor>Kathleen Turner</actor>
        <actor>Danny DeVito</actor>
    </video>
    <video>
        <title>Her Alibi</title>
        <director>Bruce Beresford</director>
        <length>94</length>
        <format>DVD</format>
        <rating>PG-13</rating>
    </video>
    <video>
        <title>Other People&#039;s Money</title>
        <director>Alan Brunstein</director>
        <year-released>1991</year-released>
        <actor>Danny DeVito</actor>
        <actor>Gregory Peck</actor>
        <actor>Penelope Ann Miller</actor>
        <actor>Dean Jones</actor>
        <actor>Piper Laurie</actor>
    </video>
    <video>
        <title>Duplex</title>
        <director>Danny DeVito</director>
        <narrator>Danny DeVito</narrator>
    </video>
</videos>

Notice many occurrences of the name Danny DeVito. We already know how to get a list of videos where a certain name corresponds to the <director> node and have a value of our choice. Here is an example:

using System.Xml;

namespace VideoCollection1
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void btnVideos_Click(object sender, EventArgs e)
        {
            XmlDocument xdVideos = new XmlDocument();

            xdVideos.Load("../../../Videos1.xml");

            XmlElement xeVideo = xdVideos.DocumentElement!;
            XmlNodeList xnlVideos = xeVideo.SelectNodes("/videos/video[director='Danny DeVito']")!;

            foreach (XmlNode xnVideo in xnlVideos)
            {
                MessageBox.Show(xnVideo.OuterXml,
                                "Video Collection",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
    }
}

This would produce:

Joining Two Operations on the Same Node Level

OR Either Child Node

Notice that the string "Danny DeVito" is the value of two <director> nodes on the same child levels of the <videos> root: "The War of the Roses" and "Duplex". We also now know how to get a list of actors with a certain name. Here is an example:

using System.Xml;

namespace VideoCollection1
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void btnVideos_Click(object sender, EventArgs e)
        {
            XmlDocument xdVideos = new XmlDocument();

            xdVideos.Load("../../../Videos1.xml");

            XmlElement xeVideo = xdVideos.DocumentElement!;
            XmlNodeList xnlVideos = xeVideo.SelectNodes("/videos/video[actor='Danny DeVito']")!;

            foreach (XmlNode xnVideo in xnlVideos)
            {
                MessageBox.Show(xnVideo.OuterXml,
                                "Video Collection",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
    }
}

This would produce:

Joining Two Operations on the Same Node Level

Joining Two Operations on the Same Node Level

Notice that the string "Danny DeVito" is the value of two <actor> nodes that are one fhe same level but on different parent nodes. He is an actor in one of the videos where he is not a director: "Other People's Money".

Practical LearningPractical Learning: Introducing Conjunctions and Disjunctions

  1. Start Microsoft Visual Studio
  2. Create a Windows Forms App named LogicalConjunctionsDisjunctions

A Junction of Two Operations (Same Node Level)

If you have the same value that occurs in different nodes but the nodes are on the same level, you can create a logical operation that represents a combination of criteria. A logical conjunction consists of combining two Boolean operations that must both produce true results. To create a logical conjunction, create some square brackets applied to the parent name of a node and create the conjunction operation in the square brackets. There are two main ways you can perform the operation.

To apply the same criterion to two different nodes that are on the same level, in the square brackets, type the name of the first node and apply the desired Boolean operation to it, followed by the name of the other node and apply the same Boolean operation to it. Separate the operations with the and operator. Here is an example:

using System.Xml;

namespace VideoCollection1
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void btnVideos_Click(object sender, EventArgs e)
        {
            XmlDocument xdVideos = new XmlDocument();

            xdVideos.Load("../../../Videos.xml");

            XmlElement xeVideo = xdVideos.DocumentElement!;
            XmlNodeList xnlVideos = xeVideo.SelectNodes("/videos/video[director='Danny DeVito' and actor='Danny DeVito']")!;

            foreach(XmlNode xnVideo in xnlVideos)
            {
                MessageBox.Show(xnVideo.OuterXml,
                                "Video Collection",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
    }
}

This would produce:

Joining Two Operations on the Same Node Level

A Junction of Two Operations (Different Node Levels)

This time, consider the following XML document:

<?xml version="1.0" encoding="utf-8" ?>
<videos>
    <video>
        <title>The War of the Roses</title>
        <director>Danny DeVito</director>
        <cast-members>
            <actor>Michael Douglas</actor>
            <actor>Kathleen Turner</actor>
            <actor>Danny DeVito</actor>
        </cast-members>
    </video>
    <video>
        <title>Her Alibi</title>
        <director>Bruce Beresford</director>
        <length>94</length>
        <format>DVD</format>
        <rating>PG-13</rating>
    </video>
    <video>
        <title>Other People&#039;s Money</title>
        <director>Alan Brunstein</director>
        <year-released>1991</year-released>
        <cast-members>
            <actorgt;Danny DeVito</actor>
            <actor>Gregory Peck</actor>
            <actor>Penelope Ann Miller</actor>
            <actor>Dean Jones</actor>
            <actor>Piper Laurie</actor>
        </cast-members>
    </video>
    <video>
        <title>Duplex</title>
        <director>Danny DeVito</director>
        <cast-members>
            <narrator>Danny DeVito</narrator>
        </cast-members>
    </video>
    <video>
        <title>Throw Momma from the Train</title>
        <writer>Stu Silver</writer>
        <cast-members>
            <actor>Billy Crystal</actor>
        </cast-members>
            <director>Danny DeVito</director>
        <cast-members>
            <actor>Kim Greist</actor>
        </cast-members>
        <music>David Newman</music>
        <cast-members>
            <actorgt;Danny DeVito</actor>
            <actor>Rob Reiner</actor>
        </cast-members>
    </video>
</videos>

Notice that the name Danny DeVito appears in many sections and somtimes the same name appears more than once in the same video section. Also notice that the director and the actor nodes don't appear on the sam levels. In fact, this XML document is organized so that the actor nodes appear as chidren of cast-member nodes. As a result, if you perform a search using the "/videos/video[director='Danny DeVito' and actor='Danny DeVito']" expression that we used for the previous XML document, you would not get any result; this is because the directors and the actors node appear on different levels.

If you need to perform a search on values that appear on different node levels, create the expression as we did previously but, for a node that appears on a lower level, precede its name with //. Here is an example:

using System.Xml;

namespace VideoCollection1
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void btnVideos_Click(object sender, EventArgs e)
        {
            XmlDocument xdVideos = new XmlDocument();

            xdVideos.Load("../../../Videos.xml");

            XmlElement xeVideo = xdVideos.DocumentElement!;
            XmlNodeList xnlVideos = xeVideo.SelectNodes("/videos/video[director='Danny DeVito' and //actor='Danny DeVito']")!;

            foreach(XmlNode xnVideo in xnlVideos)
            {
                MessageBox.Show(xnVideo.OuterXml,
                                "Video Collection",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
    }
}

This would produce:

A Junction of Two Operations (Different Node Levels)

A Junction of Two Operations (Different Node Levels)

A Junction of Two Operations (Different Node Levels)

Joining Criteria for a Specific Result

In the above XML document, notice that Danny Devito is a director and an actor in more than one video. If you have an XML document with a value that appear in many different child nodes, you can use an and operator to combine. In that case, you would create two expression that each uses the a node of your choice but they apply the same value to each. Separate the operations with the and operator. Here is an example:

using System.Xml;

namespace LogicalConjunctionsDisjunctions
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void btnVideos_Click(object sender, EventArgs e)
        {
            XmlDocument xdVideos = new XmlDocument();

            xdVideos.Load("../../../Videos.xml");

            XmlElement xeVideo = xdVideos.DocumentElement!;
            XmlNodeList xnlVideos = xeVideo.SelectNodes("/videos/video[director='Danny DeVito' and title='The War of the Roses']")!;

            foreach (XmlNode xnVideo in xnlVideos)
            {
                MessageBox.Show(xnVideo.OuterXml,
                                "Video Collection",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
    }
}

This would produce:

Joining Two Operations on the Same Node Level

In the same way, you can create as many conjunctions as you want, by separating the operations with the and operator.

Logical Disjunctions

Introduction

Logical disjunction consists of applying the same criterion to two nodes or applying different criteria to the same node so that at least one of the operations needs to be true. To create a logical disjunction, apply the square brackets to the parent node. As seen for the conjunction, you have many options.

Finding Either Value from a Common Node Level

To start a logical operation, first type the name of a parent node followed by square brackets. In the square brackets, create expressions where you assign a different value to the same node. Between two of the assignments, use the or operator. Here is an example that gets videos in which either Eddie Murphy or Danny DeVito are actors:

using System.Xml;

namespace VideoCollection1
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void btnVideos_Click(object sender, EventArgs e)
        {
            XmlDocument xdVideos = new XmlDocument();

            xdVideos.Load("../../../Videos.xml");

	        XmlElement xeVideo = xdVideos.DocumentElement!;
	        XmlNodeList xnlVideos = xeVideo.SelectNodes("//cast-members[actor='Danny DeVito' or actor='Eddie Murphy']")!;

	        foreach(XmlNode xnVideo in xnlVideos)
            {
	                MessageBox.Show(xnVideo.OuterXml,
                                "Video Collection",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
    }
}

This would produce:

Logical Disjunctions - Finding Either Value from a Common Node

Logical Disjunctions - Finding Either Value from a Common Node

Logical Disjunctions - Finding Either Value from a Common Node

Notice that the result is exactly the same as that of the | operator reviewed in the previous lesson.

Finding Either Value from Different Node Levels

In the previous section, we applied a disjunction to nodes on the same level. If you want to apply the comparison on nodes of different levels, make sure you provide the node and its parent. Of course, apply the or operator. Here is an example that gets videos directed by either Danny DeVito or Roland Emmerich:

using System.Xml;

namespace VideoCollection1
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void btnVideos_Click(object sender, EventArgs e)
        {
            XmlDocument xdVideos = new XmlDocument();

            xdVideos.Load("Videos.xml");

            XmlElement xeVideo = xdVideos.DocumentElement!;
            XmlNodeList xnlVideos = xeVideo.SelectNodes("/videos/video[director='Danny DeVito' or director='Roland Emmerich']")!;

            foreach(XmlNode xnVideo in xnlVideos)
            {
                MessageBox.Show(xnVideo.OuterXml,
                                "Video Collection",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
    }
}

This would produce:

Logical Disjunctions - Finding Either Value from Different Node Levels

Logical Disjunctions - Finding Either Value from Different Node Levels

Logical Disjunctions - Finding Either Value from Different Node Levels

By using the Boolean search operators (and, or, and the not() functions) and the logical conjunction/disjunction operations, you can create tremendous combinations to include and exclude some nodes in the XPath expression and get the desired results.

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2014-2024, FunctionX Thursday 27 June 2024, 11:35 Next