| ||||||||
Other MarkupAs part of the CMarkup release 8.0 support for Generic Markup In CMarkup, any non-XML arrangement of tags can be navigated using CMarkup. See also HTML And CMarkup. It is possible to use an abbreviated markup system in which end tags are intentionally omitted for brevity. This is not recommended because it means leaving the XML standard for questionable benefit, but it can be navigated using CMarkup methods. Compare the well-formed RECORD and then the alternative markup option following it: <RECORD><NAME>John Smith</NAME><ID>7632</ID><SCORE>10.6</SCORE></RECORD>
<RECORD><NAME>John Smith<ID>7632<SCORE>10.6</RECORD>
If there is no end tag, and it is not an XML empty element ending in xml.FindElem( "RECORD" ); xml.IntoElem(); xml.FindElem( "NAME" ); xml.FindNode(); CString csName = xml.GetData(); xml.FindElem( "ID" ); xml.FindNode(); CString csID = xml.GetData(); xml.FindElem( "SCORE" ); xml.FindNode(); CString csScore = xml.GetData(); Essentially, once you find the non-ended element, you extract the text node that comes after it. The complication is that if the element is immediately followed by the next non-ended element without a text node in between, you will not be in a good position to find the next element. For example, suppose it is possible in your data to have a NAME and SCORE and an empty ID. <RECORD><NAME>James Smith<ID><SCORE>4.6</RECORD>
After finding the ID element, you call CString csName, csID, csScore; xml.FindElem( "RECORD" ); xml.IntoElem(); xml.FindElem( "NAME" ); if ( xml.FindNode() == xml.MNT_TEXT ) csName = xml.GetData(); xml.ResetMainPos(); xml.FindElem( "ID" ); if ( xml.FindNode() == xml.MNT_TEXT ) csID = xml.GetData(); xml.ResetMainPos(); xml.FindElem( "SCORE" ); if ( xml.FindNode() == xml.MNT_TEXT ) csScore = xml.GetData(); It would be more efficient if it was known that there will be no ID element when the ID value is empty. In that case you could test the result of the <RECORD><NAME>James Smith<SCORE>4.6</RECORD>
CString csName, csID, csScore;
xml.FindElem( "RECORD" );
xml.IntoElem();
if ( xml.FindElem("NAME") )
{
xml.FindNode();
csName = xml.GetData();
}
if ( xml.FindElem("ID") )
{
xml.FindNode();
csID = xml.GetData();
}
if ( xml.FindElem("SCORE") )
{
xml.FindNode();
csScore = xml.GetData();
}
This can be handled with CMarkup release 8.0 much like the previous example with the addition of the // Retrieve severity and message
CString csMsg, csSev;
xml.FindElem(); // root
xml.IntoElem();
xml.FindElem( "STATUS" );
xml.IntoElem();
if ( xml.FindElem("SEVERITY")
&& xml.FindNode() == xml.MNT_TEXT )
csSev = TruncToLastEOL( xml.GetData() );
xml.ResetMainPos();
if ( xml.FindElem("MESSAGE")
&& xml.FindNode() == xml.MNT_TEXT )
csMsg = TruncToLastEOL( xml.GetData() );
CString TruncToLastEOL( CString csVal )
{
// locate and truncate from final EOL
// also cuts any trailing indentation
int nLength = csVal.GetLength();
const _TCHAR* pszVal = (const _TCHAR*)csVal;
int nLastEOL = nLength;
int nChar = 0;
while ( nChar < nLength )
{
// Go to next EOL
nLastEOL = nLength;
while ( nChar < nLength && pszVal[nChar] != _T('\r')
&& pszVal[nChar] != _T('\n') )
nChar += (int)_tclen(&pszVal[nChar]);
nLastEOL = nChar;
while ( nChar < nLength
&& _tcschr(_T(" \t\n\r"),pszVal[nChar]) )
++nChar;
}
if ( nLastEOL < nLength )
csVal = csVal.Left( nLastEOL );
return csVal;
}
Yes, one of the advantages of CMarkup is the option to ignore case when parsing and navigating documents; other XML tools don't allow this but CMarkup is designed for XML as well as non-compliant XML and other kinds of markup. Turn the ignore case flag on for a CMarkup object m.SetDocFlags( CMarkup::MDF_IGNORECASE ); Or to compile this as the default for all CMarkup objects: #define MARKUP_IGNORECASE Because HTML tag and attribute names are not case sensitive, this is especially useful for HTML And CMarkup. | ||||||||||
|
Posted July 12, 2005. Question or comment about this article? ©Copyright 2008 First Objective Software, Inc. All rights reserved. |