Navigating Levels in CMarkup

XML supports hierarchical information much like what is known as a "tree" in computer jargon. This is by virtue of the XML element which can contain elements which can contain elements and so on. In the XML Specification, an element that is contained by another element is a "child" of that element. The element containing an element is the "parent" of that element.

CMarkup tracks a current position within the document in order to know which part of the document the CMarkup methods act upon. The current position consists of a parent position, a main position, and a child position. Upon loading a document, there is no current position, until you call FindElem or FindChildElem.

After creating the document in the following illustration and calling FindChildElem(), the main position is the root ORDER element and the child position is its first ITEM element as shown on the left. The parent position is represented in a cloud above the whole document, because its children are the root element and any other nodes in the top level of the document. After calling IntoElem, the resulting positions are shown on the right. The main position moves to the ITEM element that was the child position. There is no longer a child position. The parent position moves to the ORDER element that was the main position.

Illustration 1: IntoElem
 
parent position goes from entire doc to root element

When there is no child position, it is as if the current child position is before the first child of the main position. So if you call FindChildElem(), the child position moves to the first child which is the NAME element. This is shown on the left in the following illustration. Calling IntoElem() will cause the parent position to move to the ITEM element that was the main position. The main position moves to the NAME element that was the child position. The child position is cleared again. This resulting current position is shown on the right in the following illustration.

Illustration 2: IntoElem
 
parent position goes from root element to ITEM element

With the same starting position as in the previous illustration, calling OutOfElem produces the position shown on the right in the following illustration. The main position moves up one level to where the parent position was. The child position moves up to the ITEM element where the main position was. The parent position moves back to that somewhat abstract position above the whole document.

Illustration 3: OutOfElem
parent position goes from ITEM element to root element

These previous examples all started with current main and child positions. If there is no main position there is no child position; there is only a parent position. When you call OutOfElem() with no main position, the main position is set to where the parent position was and the parent position moves to its parent. You cannot call IntoElem() when there is no main position because there is no main position to move into. The only time you cannot call OutOfElem() is when the parent position is already above the whole document.

See also Navigating and Getting Information From a Document.

 

comment posted CMarkup Element Level

David Blankenship 26-May-2006

I have been looking through the documentation and the code for the CMarkupSTL class, and I have not found a good way to query the level of the current element. The information is there. Is there an existing way to access it? This is the method that I want:

int GetElemLevel() { return m_aPos[m_iPos].Level(); }

While I am asking questions, is there a way to get the total depth of the XML tree? i.e. maximum level

Good observation, you showed the exact way of implementing GetElemLevel.

Update October 19, 2006: GetElemLevel was added in CMarkup release 8.3 developer version.

The max level is not tracked. With your GetElemLevel function the maximum level could be computed like this:

int nMax = 0;
xml.ResetPos();
while ( xml.FindElem("//*") ) // Paths In CMarkup
  nMax = max( nMax, xml.GetElemLevel() );

Another function that can be implemented using information that is tracked is GetDocElemCount (this uses the m_iPosDeleted which is only in the developer version).

int nTotalDeleted = 0;
int iPosDeleted = m_iPosDeleted;
while ( iPosDeleted )
{
  ++nTotalDeleted;
  iPosDeleted = m_aPos[iPosDeleted].iElemNext;
}
int nElemCount = m_iPosFree - nTotalDeleted;

Update April 1, 2007: GetDocElemCount was added in CMarkup release 9.0 developer version.

 

comment posted Re: CMarkup Element Level

David Blankenship 30-May-2006

my real question is is there any way to get the level of an element using the public interface of the CMarkupSTL class? It looks like I do not have access to the element flags that contain the level information, and I do not have access to the class defined mask to be able to get the level from the flags even if I did. I really don't want to have to extend the class to get access to the protected data.

Update October 19, 2006: GetElemLevel was added in CMarkup release 8.3 developer version.

You can determine the level externally, without GetElemLevel, like this:

int nIndex = xml.GetElemIndex();
int nLevel = 0;
while ( xml.OutOfElem() )
  ++nLevel;
xml.GotoElemIndex( nIndex );

The index part is only if you need to return back to the main position.

 

comment posted Enter() and Leave() methods

Robin Hilliard 12-Jun-2009

...Also (and this is just a personal preference of mine, so please ignore it), I've renamed the functions "IntoElem()" and "OutOfElem()" to "Enter()" and "Leave()" respectively. I find 'em easier to type and read.

Enter and Leave are very intuitive names for IntoElem and OutOfElem.