processArea.cc [tools/Rusle2SoilsXMLCreator/pg/rusle2_from_ssurgo_build_newbackup] Revision: default Date:
#include "libpq-fe.h"
#include <algorithm>
#include <iostream>
#include <string>
#include <cmath>
#include "stdio.h"
#include "rusle2_from_ssurgo.h"
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost;
/*
* Lets get the xml filename fit for Linux
*/
char
win2nixSlash( char in )
{
if( in == '\\' )
return '/';
return in;
}
/**
* Convert the NASIS hydrologic class to the Rusle2 hydrologic class.
* The NASIS classes are "A" - "D".
* This returns the highest class on error, to preserve existing functionality.
*/
string
Rusle2HydrologicClass ( string pszHydrologicClass )
{
if(pszHydrologicClass.length() == 0 )
return "HYDROLOGIC_CLASS_HIGH_RO";
/* TODO: change to return "NaN" on error. */
switch ( *pszHydrologicClass.c_str() )
{
case 'A': return "HYDROLOGIC_CLASS_LOW_RO";
case 'B': return "HYDROLOGIC_CLASS_MOD_LOW_RO";
case 'C': return "HYDROLOGIC_CLASS_MOD_HIGH_RO";
case 'D': return "HYDROLOGIC_CLASS_HIGH_RO";
default: return "HYDROLOGIC_CLASS_HIGH_RO";
/* TODO: change to return "NaN" on error. */
}
}
string
EscapeSingleQuotes ( string inStr )
{
if(inStr.length() == 0)
return inStr;
string _inStr = "";
for (int i=0; i < inStr.length(); i++)
{
if (inStr[i]=='\'')
_inStr += "'";
_inStr += inStr[i];
}
return _inStr;
}
/**
* processArea()
* Import Rusle2 soil records from a NASIS (SSURGO) soil MDB export file.
* SSURGO is an output format for subsets of the NASIS information.
* These formats are documented at URL "http://nasis.usda.gov/documents/metadata/".
* In NASIS, "map units" (geographical regions) can have an unlimited number of "components" (soil types),
* and components can have an unlimited number of "horizons" (soil layers).
* For now, make a mapunit folder and in it, put each component (each row of the component table) as a soil object,
* with a name "component name (% occurring)"
* Returns the number of files successfully imported, or FAILURE (-1) on errors.
* @since 2005-05-09 the rules for what should be imported has changed. In the order they should be done, they are:
* 1) in the component table, look for compkind = "miscellaneous area". This will be for water, pits, etc, that should be thrown out completely
* 2) if the soil is a Histosol (taxorder == "Histosol"), just grab the first horizon and get whatever we can out of that
* 3) if not a Histosol, search through the horizons, looking for one that has a valid kfactor, then use that. This is to sort out soils where the
* top layers are organic matter; it will grab the first mineral layer
*
* NAMING
* Rusle2 soil filenames are currently algorithmically generated as follows:
*
* sFullname = "soils\\" + surveyArea + "\\" + muFolderName + "\\" + fullComponentName;
*
* The values below are from the import code in ReadNASISSoilData(), edited for readability:
*
* surveyArea = sSANAME;
* muFolderName = sMUSYM + " " + sMUNAME;
* fullComponentName = componentName + " " + texture + " " + localPhase + " " + dominanceStr + "%";
*
* sMUSYM = GetNasisString("musym", ...); // Map unit symbol
* sMUNAME = GetNasisString("muname", ...); // Map unit name
* sSANAME = GetNasisString("areaname", ...);
*
* componentName = GetNasisString("compName", ...);
* texture = GetNasisString("texdesc", ...);
* localPhase = GetNasisString("localPhase", ...);
* dominanceStr = GetFieldValue("comppct_r", ...);
*
* The user is able to enter (override) the surveyArea variable when importing, which determines the
* folder name. This is the only part of the import that allows the user to enter a name to use.
* However, I believe the default name is almost universally used when importing these files.
* The default name is taken from the value of the "areaname" field in the SSURGO download. The names
* in this field are highly inconsistent in NASIS, and this is the source of the inconsistent
* naming in Rusle2.
*
* @note At the time of the import we have the FIPS code available to us (which is stored in Rusle2
* parameter "NASIS_SASYM" (e.g. NH602). This appears to be a concatenation of the FIPS 2-letter code
* for the state with the FIPS 3-digit code for the county. It would be easy to use this to generate
* a more consistent name for the area than is currently in the SSURGO "surveyArea" field.
*
* @note May 2011 - This has been re-written by Eric Hudish <hudish@zedxinc.com> in cooperation with NRCS, Jim Lyon <jplyon.csu@gmail.com> advising.
* Code has been changed to work with a PostgresSQL + Postgis database as opposed to Microsoft Access mdb format.
* Some of the functions have been kept to mimic the procedured, others removed completely.
* Messages about number of failures have been removed completely.
* libxml2 was implemented to generate XML instead of custom functions
*/
bool
processArea( PGconn* conn, PGresult* res, string dir_out, int pROW)
{
#ifndef NDEBUG
cout << "processArea()" << endl;
#endif
if( pROW >= PQntuples(res) )
return false;
string aSym = GetNasisString("areasymbol", res, pROW);
string aName = GetNasisString("areaname", res, pROW);
string aExt = ".xml";
string aLKEY = GetNasisString("lkey", res, pROW);
cerr << "Processing:'" << aSym << "'" << endl;
cerr << "lkey:'" << aLKEY << "'" << endl;
/*
* Start the soil string
*/
string sFullname = dir_out + aName + "\\";
/*
* Query out the [MAPUNIT] information
*/
//string muQuery = "SELECT musym, m.mukey, muname, compname, kffact, tfact, slope_r, c.cokey, sandtotal_r, hydgrp, taxorder, kwfact, om_r, hzthk_r from ssurgo.mapunit m, ssurgo.component c, ssurgo.chorizon h where m.mukey = c.mukey and c.cokey = h.cokey and h.hzdept_r=0 and lkey=$1";
//string muQuery = "SELECT musym, m.mukey, muname, compname, tfact, slope_r, c.cokey from ssurgo.mapunit m, ssurgo.component c where m.mukey = c.mukey and lkey=$1";
//string muQuery = "SELECT musym, mukey, muname from ssurgo.mapunit where lkey=$1";
// Original PG query
string muQuery = "SELECT musym, m.mukey, muname, compname, compkind, majcompflag, localphase, kffact, tfact, slope_r, c.cokey, sandtotal_r, hydgrp, taxorder, kwfact, om_r, hzthk_r, otherph, comppct_r from ssurgo.mapunit m, ssurgo.component c, ssurgo.chorizon h where m.mukey = c.mukey and c.cokey = h.cokey and h.hzdept_r in (select hzdept_r from ssurgo.minhzdept_t where minhzdept_t.cokey=c.cokey and minhzdept_t.areasymbol='" + aSym + "' and minhzdept_t.musym=m.musym and minhzdept_t.mukey=m.mukey) and lkey=$1";
// FDW - PG to SQL SVR query
//string muQuery = "SELECT musym, m.mukey, muname, compname, kffact, tfact, slope_r, c.cokey, sandtotal_r, hydgrp, taxorder, kwfact, om_r, hzthk_r from ss_mapunit m, ss_component c, ss_chorizon h where m.mukey = c.mukey and c.cokey = h.cokey and h.hzdept_r in (select hzdept_r from ss_minhzdept_t where minhzdept_t.cokey=c.cokey and minhzdept_t.areasymbol='" + aSym + "' and minhzdept_t.musym=m.musym and minhzdept_t.mukey=m.mukey) and lkey=$1";
//string muQuery = "with mindepths as (select hzdept_r, cokey, musym, mukey from ssurgo.minhzdept_t where minhzdept_t.areasymbol='" + aSym + "') SELECT musym, m.mukey, muname, c.compname, c.compkind, c.majcompflag, c.localphase, kffact, tfact, c.slope_r, c.cokey, sandtotal_r, hydgrp, taxorder, kwfact, om_r, hzthk_r, h.hzdept_r, avgfragvol_r from ssurgo.mapunit m, ssurgo.component c, ssurgo.chorizon h, ssurgo.avgfragvol f where m.mukey = c.mukey and c.cokey = h.cokey and c.cokey = f.cokey and h.hzdept_r in (select hzdept_r from mindepths min where min.cokey=c.cokey and min.musym=m.musym and min.mukey=m.mukey ) and lkey=$1";
//string muQuery = "with mindepths as (select hzdept_r, cokey, musym, mukey from ssurgo.minhzdept_t where minhzdept_t.areasymbol='" + aSym + "') SELECT musym, m.mukey, muname, c.compname, c.compkind, c.majcompflag, c.localphase, kffact, tfact, c.slope_r, c.cokey, sandtotal_r, hydgrp, taxorder, kwfact, om_r, hzthk_r, h.hzdept_r, avgfragvol_r, c.otherph, c.comppct_r from ssurgo.mapunit m join ssurgo.component c on (m.mukey = c.mukey) join ssurgo.chorizon h on (c.cokey = h.cokey) left outer join ssurgo.avgfragvol f on (c.cokey = f.cokey) where h.hzdept_r in (select hzdept_r from mindepths min where min.cokey=c.cokey and min.musym=m.musym and min.mukey=m.mukey) and lkey=$1";
cerr << "query:" << muQuery << endl;
const char * paramValues[1];
paramValues[0] = aLKEY.c_str();
int numParams = 1;
PGresult *muRes;
muRes = PQexecParams( conn,
muQuery.c_str(),
numParams,
NULL,
paramValues,
NULL,
NULL,
0);
if( PQresultStatus(muRes) != PGRES_TUPLES_OK ){
PQclear(muRes);
exit_nicely(conn);
}
cerr << "query *" << aSym << "* ROW_COUNT=" << PQntuples(muRes) << endl;
for( int i=0; i<PQntuples(muRes); i++){
/* copy the string for the local version of this string */
string _sFullname = sFullname;
/* get the [MAPUNIT] components */
string muSym = GetNasisString("musym", muRes, i);
string muName = GetNasisString("muname", muRes, i);
string muKEY = GetNasisString("mukey", muRes, i);
string compname = GetNasisString("compname", muRes, i);
string compkind = GetNasisString("compkind", muRes, i);
string majcompflag = GetNasisString("majcompflag", muRes, i);
string localphase = GetNasisString("localphase", muRes, i);
string _kffact = GetNasisString("kffact", muRes, i);
string tfact = GetNasisString("tfact", muRes, i);
string sloper = GetNasisString("slope_r", muRes, i);
string cokey = GetNasisString("cokey", muRes, i);
string sandtotal_r = GetNasisString("sandtotal_r", muRes, i);
string _hydgrp = GetNasisString("hydgrp", muRes, i);
string taxorder = GetNasisString("taxorder", muRes, i);
string kwfact = GetNasisString("kwfact", muRes, i);
string om_r = GetNasisString("om_r", muRes, i);
string hzthk_r = GetNasisString("hzthk_r", muRes, i);
//string avgfragvol_r = GetNasisString("avgfragvol_r", muRes, i);
string avgfragvol_r = "0";
string otherph = GetNasisString("otherph", muRes, i);
string comppct_r = GetNasisString("comppct_r", muRes, i);
if (tfact.length() == 0)
tfact = "0";
if (sloper.length() == 0)
sloper = "0";
if (sandtotal_r.length() == 0)
sandtotal_r = "0";
if (om_r.length() == 0)
om_r = "0";
if (hzthk_r.length() == 0)
hzthk_r = "0";
if (avgfragvol_r.length() == 0)
avgfragvol_r = "0";
cerr << "Processing " << cokey << " --- " << compname << " --- " << aSym << endl;
//cerr << "_hydgrp=" << _hydgrp << endl;
//cerr << "taxorder=" << taxorder << endl;
//cerr << "kwfact=" << kwfact << endl;
//cerr << "om_r=" << om_r << endl;
//cerr << "hzthk_r=" << hzthk_r << endl;
/* add on the [MAPUNIT] components */
_sFullname += muSym + " " + muName;
_sFullname = (char*)xmlEncodeSpecialChars(NULL, ConvertInput(_sFullname.c_str(), MY_ENCODING) );
int cRow = 0;
PGresult *coRes = queryComponents(conn, muKEY);
int numComponents = PQntuples(coRes);
/* Note: The horizKey is passed back so we can query the specific horizon by chkey
* This allows us to do all the XML here rather than generate downstream and pass it back
*
* Just makes more sense to me this way, then we know we've hit a good component/horizon pair
* and don't waste our time generating xml which won't be used if we fail to find a good horizon
* or something like that...
*
*/
string compString, horizKey;
while( getComponentString(compString, horizKey, coRes, cRow, conn) == true ){
//string compname = GetNasisString("compname", coRes, cRow);
//string tfact = GetNasisString("tfact", coRes, cRow);
//string sloper = GetNasisString("slope_r", coRes, cRow);
//string cokey = GetNasisString("cokey", coRes, cRow);
/*
* 1) in the component table, look for compkind = "miscellaneous area".
* This will be for water, pits, etc, that should be thrown out completely
*/
if( GetNasisString("compkind", coRes, cRow) == "Miscellaneous area" ){
cRow++;
continue;
}
/* Yay, we have a valid component string */
if(compString.length() > 0 ){
compString = (char*)xmlEncodeSpecialChars(NULL, ConvertInput(compString.c_str(), MY_ENCODING) );
trim(compString);
string xmlFilename = _sFullname + "\\" + compString + aExt;
string sFullname = xmlFilename;
transform( xmlFilename.begin(), xmlFilename.end(), xmlFilename.begin(), win2nixSlash );
/* This is just the directory */
string tmpDir = _sFullname.c_str();
transform( tmpDir.begin(), tmpDir.end(), tmpDir.begin(), win2nixSlash );
if( VERBOSE > 0 )
cout << "\t" << tmpDir << endl;
/*
* There is a create_directories function in boost/filesystem/convenience.hpp
* I'd like to try using that...but CentOS has an older version where boost/filesystem
* isn't really supported.
* Plus there are some comments online that it still doesn't work properly with spaces
* in the name....but might be worth a shot.
*
* TODO : Verify the filename is correctly encoded.
* < -> <
* > -> >
* " -> "
*
* I believe use of xmlEncodeSpecialChars() is *good enough*, but it would take a pretty good
* case example to verify. Seeing as how NRCS would know better than me I'll just leave this
* note and hope they can patch it if necessary.
*/
char cmd[255];
sprintf(cmd, "mkdir -p \"%s\"", tmpDir.c_str() );
system(cmd);
/* *** XML
* Here we generate the XML with libxml2
* I only check the init rc values for success.
* Once generated, at this point the rest of the elements should complete because
* we got through all the components, horizons etc get a true value back
*
* If there is something that needs to be checked, simply compare the rc value.
*
*** */
int rc;
xmlTextWriterPtr writer;
xmlChar *tmp;
/* init the XML Writer
* libxml2 - See xmlsoft.org/examples
*/
writer = xmlNewTextWriterFilename(xmlFilename.c_str(), 0);
if( rc < 0 ){
cerr << "Error creating the xml writer=[" << rc << "] filename:" << xmlFilename.c_str() << endl;
exit_nicely(conn);
}
/* Start the document with the xml default for the version,
* encoding ISO 8859-1 and the default for the standalone
* declaration. */
rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL);
if (rc < 0) {
cerr << "testXmlwriterFilename: Error at xmlTextWriterStartDocument filename:" << xmlFilename.c_str() << endl;;
exit_nicely(conn);
}
/* Start root element named "Obj" */
rc = xmlTextWriterStartElement(writer, BAD_CAST "Obj");
if (rc < 0) {
cerr << "testXmlwriterFilename: Error at xmlTextWriterStartElement filename:" << xmlFilename.c_str() << endl;
exit_nicely(conn);
}
rc = xmlTextWriterWriteElement(writer, BAD_CAST "Type", ConvertInput("SOIL", MY_ENCODING) );
rc = xmlTextWriterWriteElement(writer, BAD_CAST "Filename", ConvertInput(sFullname.c_str(), MY_ENCODING) );
rc = xmlTextWriterWriteElement(writer, BAD_CAST "Science", ConvertInput(SCIENCEVERSION, MY_ENCODING) );
/* **** Start COMPONENT XML **** */
/* slopelenusle */
rc = AttrXML(writer, "Flt", "TYPICAL_LENGTH",
GetNasisString("slopelenusle_l", coRes, cRow),
GetNasisString("slopelenusle_r", coRes, cRow),
GetNasisString("slopelenusle_h", coRes, cRow),
"",
"U_METER" );
/* slope */
rc = AttrXML(writer, "Flt", "TYPICAL_STEEPNESS",
GetNasisString("slope_l", coRes, cRow),
sloper,
//GetNasisString("slope_r", coRes, cRow),
GetNasisString("slope_h", coRes, cRow),
"",
"U_PERCENT" );
/* tfact */
rc = AttrXML(writer, "Flt", "SOIL_T_VALUE",
GetNasisString("tfact", coRes, cRow),
"",
"U_TON_P_AC_YR" );
/* Hydrological Class */
string sTiledHydrologicClass, sHydrologicClass;
sTiledHydrologicClass = sHydrologicClass = "Nan";
string hydgrp = GetNasisString("hydgrp", coRes, cRow);
if ( hydgrp.length() != 0 ){
/* Extract undrained and drained hyd groups from possibly concatenated string "A/D" */
string undrained, drained;
if (hydgrp.length() == 3){
/* If A/D, first category is drained (low runoff), latter category is undrained (high runoff) */
drained = hydgrp[0];
undrained = hydgrp[2];
}else{
/* drained is undefined, so set same as undrained */
undrained = hydgrp[0];
drained = undrained;
}
sTiledHydrologicClass = Rusle2HydrologicClass(drained);
sHydrologicClass = Rusle2HydrologicClass(undrained);
}
/* TiledHydrologicClass */
rc = AttrXML(writer, "Lst", "TILED_HYDROLOGIC_CLASS",
sTiledHydrologicClass,
"",
"" );
/* HydrologicClass */
rc = AttrXML(writer, "Lst", "HYDROLOGIC_CLASS",
sHydrologicClass,
"",
"" );
/* Soil Description */
rc = AttrXML(writer, "Str", "SOIL_DESCRIP",
GetNasisString("geomdesc", coRes, cRow),
"",
"" );
/* **** END COMPONENT XML **** */
/* **** START HORIZON XML **** */
PGresult *hzXMLRes = queryHorizonForXML(conn, horizKey);
/*
* Get more values from the chorizon table. Need to set the NASIS organic matter value into two places. The first is just a place-holder,
* while the second is the value actually used in the calculations
*/
/* Organic Matter */
rc = AttrXML(writer, "Flt", "NASIS_OM_REP_HOR_1",
GetNasisString("om_l", hzXMLRes, 0),
GetNasisString("om_r", hzXMLRes, 0),
GetNasisString("om_h", hzXMLRes, 0),
"",
"U_PERCENT" );
/* Organic Matter */
rc = AttrXML(writer, "Flt", "ORGANIC_MATTER",
GetNasisString("om_l", hzXMLRes, 0),
GetNasisString("om_r", hzXMLRes, 0),
GetNasisString("om_h", hzXMLRes, 0),
"",
"U_PERCENT" );
/* I don't know what this is... */
rc = AttrXML(writer, "Flt", "NASIS_PH_1TO1_H20_REP_HOR_1",
GetNasisString("ph1to1h2o_l", hzXMLRes, 0),
GetNasisString("ph1to1h2o_r", hzXMLRes, 0),
GetNasisString("ph1to1h2o_h", hzXMLRes, 0),
"",
"U_PH_UNITS" );
/* Erodibility */
string taxOrder = GetNasisString("taxorder", coRes, cRow);
string taxSubGrp = GetNasisString("taxsubgrp", coRes, cRow);
/*
* User-entry ERODIBILITY values are now stored in ERODIBILITY_HAND instead.
* We also set ERODIBILITY_OPTION_PTR to "ERODIBILITY_OPTION_SET_BY_USER", although that is the default value.
* We still set ERODIBILITY directly, even though it is now calculated, because we are faking the science date.
*/
string kffact = GetNasisString("kffact", hzXMLRes, 0);
//string sandtotal_r = GetNasisString("sandtotal_r", hzXMLRes, 0);
if( taxOrder == "Histosols" || taxSubGrp.find("Histic") != string::npos || kffact.length() == 0 ){
/* for Histosols, set the erodibility = 0.02 */
rc = AttrXML(writer, "Flt", "ERODIBILITY", "0.02", "", "U_ENGLISH_EROD" );
rc = AttrXML(writer, "Flt", "ERODIBILITY_HAND", "0.02", "", "U_ENGLISH_EROD" );
rc = AttrXML(writer, "SbR", "ERODIBILITY_OPTION_PTR", "ERODIBILITY_OPTION_SET_BY_USER", "", "" );
}else{
/* good kffact value */
rc = AttrXML(writer, "Flt", "ERODIBILITY", kffact, "", "U_ENGLISH_EROD" );
rc = AttrXML(writer, "Flt", "ERODIBILITY_HAND", kffact, "", "U_ENGLISH_EROD" );
rc = AttrXML(writer, "SbR", "ERODIBILITY_OPTION_PTR", "ERODIBILITY_OPTION_SET_BY_USER", "", "" );
}
/* TODO: The above and below can probably be condensed...
* histosols back into this at Lightle's request (051026) because wanted to be able to open these soils for SCI calculations
*/
if( taxOrder == "Histosols" || taxSubGrp.find("Histic") != string::npos || kffact.length() == 0 ){
/* Have already put in a bogus erodibility = 0.02 for these, so might as well give them bogus texture! */
rc = AttrXML(writer, "Flt", "SAND", "0.0", "", "U_PERCENT");
rc = AttrXML(writer, "Flt", "SILT", "0.0", "", "U_PERCENT");
rc = AttrXML(writer, "Flt", "CLAY", "100.0", "", "U_PERCENT");
}else{
bool changedVals = false;
string sandStr = GetNasisString("sandtotal_r", hzXMLRes, 0);
string siltStr = GetNasisString("silttotal_r", hzXMLRes, 0);
string clayStr = GetNasisString("claytotal_r", hzXMLRes, 0);
/* Note: I don't think they CAN match "NaN"...but I'll leave it for now */
if( sandStr.length() == 0 || sandStr == "NaN" ){ sandStr = "0"; changedVals = true; }
if( siltStr.length() == 0 || siltStr == "NaN" ){ siltStr = "0"; changedVals = true; }
if( clayStr.length() == 0 || clayStr == "NaN" ){ clayStr = "0"; changedVals = true; }
/* Ensure they add up */
if( !changedVals ) {
double sandVal = atof( sandStr.c_str() );
double siltVal = atof( siltStr.c_str() );
double clayVal = atof( clayStr.c_str() );
if( fabs(sandVal + siltVal + clayVal - 100.0) > 0.1)
changedVals = true;
}
if(changedVals){
/* something changed, so warn of that and store nonsense values (unless is Histosol) */
rc = AttrXML(writer, "Flt", "SAND", "0.0", "", "U_PERCENT");
rc = AttrXML(writer, "Flt", "SILT", "0.0", "", "U_PERCENT");
rc = AttrXML(writer, "Flt", "CLAY", "0.0", "", "U_PERCENT");
}else{
/* Everything OK */
rc = AttrXML(writer, "Flt", "SAND", sandStr, "", "U_PERCENT");
rc = AttrXML(writer, "Flt", "SILT", siltStr, "", "U_PERCENT");
rc = AttrXML(writer, "Flt", "CLAY", clayStr, "", "U_PERCENT");
}
}
/* Add NASIS parameters to identify this soil. */
rc = AttrXML(writer, "Str", "NASIS_MUSYM", muSym, "1", "");
rc = AttrXML(writer, "Str", "NASIS_SASYM", muName, "1", "");
/* Add new NASIS parameters desired by Dabney 2010-04-17 */
/* CeC */
rc = AttrXML(writer, "Flt", "NASIS_CEC_7",
GetNasisString("cec7_l", hzXMLRes, 0),
GetNasisString("cec7_r", hzXMLRes, 0),
GetNasisString("cec7_h", hzXMLRes, 0),
"",
"U_MEQ_P_100_ML" );
/* Water Content Third Bar */
rc = AttrXML(writer, "Flt", "NASIS_WATER_CONTENT_THIRD_BAR",
GetNasisString("wthirdbar_l", hzXMLRes, 0),
GetNasisString("wthirdbar_r", hzXMLRes, 0),
GetNasisString("wthirdbar_h", hzXMLRes, 0),
"",
"U_PERCENT" );
/* Water Content Fifteen Bar */
rc = AttrXML(writer, "Flt", "NASIS_WATER_CONTENT_15_BAR",
GetNasisString("wfifteenbar_l", hzXMLRes, 0),
GetNasisString("wfifteenbar_r", hzXMLRes, 0),
GetNasisString("wfifteenbar_h", hzXMLRes, 0),
"",
"U_PERCENT" );
/* Bulk Density Third Bar */
rc = AttrXML(writer, "Flt", "NASIS_BULK_DENSITY_THIRD_BAR",
GetNasisString("dbthirdbar_l", hzXMLRes, 0),
GetNasisString("dbthirdbar_r", hzXMLRes, 0),
GetNasisString("dbthirdbar_h", hzXMLRes, 0),
"",
"U_PERCENT" );
/* **** END HORIZON XML **** */
xmlTextWriterEndDocument(writer);
xmlFreeTextWriter(writer);
/* END XML */
/* output
* For now we'll just output as we need to
* but theoretically we could add a function here to output in different modes
*/
fprintf(ofile, "INSERT INTO map_soils VALUES('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%s,%s,'%s',%s,'%s','%s','%s',%s,%s,%s,'%s',%s);\n",
aSym.c_str(),
muSym.c_str(),
muKEY.c_str(),
EscapeSingleQuotes(_sFullname).c_str(),
EscapeSingleQuotes(compString).c_str(),
muName.c_str(),
compname.c_str(),
compkind.c_str(),
majcompflag.c_str(),
localphase.c_str(),
_kffact.c_str(),
tfact.c_str(),
sloper.c_str(),
cokey.c_str(),
sandtotal_r.c_str(),
_hydgrp.c_str(),
taxorder.c_str(),
kwfact.c_str(),
om_r.c_str(),
hzthk_r.c_str(),
avgfragvol_r.c_str(),
otherph.c_str(),
comppct_r.c_str()
);
// cout << aSym << ","_sFullname << "\\" << compString << endl;
}/* End check for compString.length */
/* Empty component strings are considered invalid
* So be sure to empty the component before the next iter
*/
cRow++;
compString.erase(0);
}
}
#ifndef NDEBUG
cout << "leaving processArea()" << endl;
#endif
return pROW < PQntuples(res) ? true : false;
}