Exemple #1
0
void NASHandler::startElement( const XMLCh* const /* uri */,
                               const XMLCh* const localname,
                               const XMLCh* const /* qname */,
                               const Attributes& attrs )

{
    char        szElementName[MAX_TOKEN_SIZE];
    GMLReadState *poState = m_poReader->GetState();

    tr_strcpy( szElementName, localname );

    if ( ( m_bIgnoreFeature && m_nDepth >= m_nDepthFeature ) ||
         ( m_osIgnoredElement != "" && m_nDepth >= m_nDepthElement ) )
    {
        m_nDepth ++;
        return;
    }

    // ignore attributes of external references and "objektkoordinaten"
    // (see PostNAS #3 and #15)
    if ( EQUAL( szElementName, "zeigtAufExternes" ) ||
         EQUAL( szElementName, "objektkoordinaten" ) )
    {
        m_osIgnoredElement = szElementName;
        m_nDepthElement    = m_nDepth;
        m_nDepth ++;

        return;
    }

#ifdef DEBUG_VERBOSE
    CPLDebug( "NAS",
              "%*sstartElement %s m_bIgnoreFeature:%d depth:%d "
              "depthFeature:%d featureClass:%s",
              m_nDepth, "", szElementName,
              m_bIgnoreFeature, m_nDepth, m_nDepthFeature,
              poState->m_poFeature ? poState->m_poFeature->
                  GetClass()->GetElementName() : "(no feature)"
            );
#endif

/* -------------------------------------------------------------------- */
/*      If we are in the midst of collecting a feature attribute        */
/*      value, then this must be a complex attribute which we don't     */
/*      try to collect for now, so just terminate the field             */
/*      collection.                                                     */
/* -------------------------------------------------------------------- */
    if( m_pszCurField != NULL )
    {
        CPLFree( m_pszCurField );
        m_pszCurField = NULL;
    }

/* -------------------------------------------------------------------- */
/*      If we are collecting geometry, or if we determine this is a     */
/*      geometry element then append to the geometry info.              */
/* -------------------------------------------------------------------- */
    const char *pszLast = NULL;

    if( m_pszGeometry != NULL
        || IsGeometryElement( szElementName ) )
    {
        const int nLNLen = tr_strlen( localname );
        CPLString osAttributes = GetAttributes( &attrs );

        /* should save attributes too! */

        if( m_pszGeometry == NULL )
            m_nGeometryDepth = poState->m_nPathLength;

        if( m_pszGeometry == NULL ||
            m_nGeomLen + nLNLen + 4 + (int)osAttributes.size() > m_nGeomAlloc )
        {
            m_nGeomAlloc = (int) (m_nGeomAlloc * 1.3 + nLNLen + osAttributes.size() + 1000);
            m_pszGeometry = (char *)
                CPLRealloc( m_pszGeometry, m_nGeomAlloc);
        }

        strcpy( m_pszGeometry+m_nGeomLen, "<" );
        tr_strcpy( m_pszGeometry+m_nGeomLen+1, localname );

        if( osAttributes.size() > 0 )
        {
            strcat( m_pszGeometry+m_nGeomLen, " " );
            strcat( m_pszGeometry+m_nGeomLen, osAttributes );
        }

        strcat( m_pszGeometry+m_nGeomLen, ">" );
        m_nGeomLen += static_cast<int>(strlen(m_pszGeometry+m_nGeomLen));
    }

/* -------------------------------------------------------------------- */
/*      Is this the ogc:Filter element in a update operation            */
/*      (wfs:Delete, wfsext:Replace or wfs:Update)?                     */
/*      specialized sort of feature.                                    */
/* -------------------------------------------------------------------- */
    else if( EQUAL(szElementName,"Filter")
             && (pszLast = m_poReader->GetState()->GetLastComponent()) != NULL
             && (EQUAL(pszLast,"Delete") || EQUAL(pszLast,"Replace") ||
                 EQUAL(pszLast,"Update")) )
    {
        const char* pszFilteredClassName = m_poReader->GetFilteredClassName();
        if ( pszFilteredClassName != NULL &&
             strcmp("Delete", pszFilteredClassName) != 0 )
        {
            m_bIgnoreFeature = true;
            m_nDepthFeature = m_nDepth;
            m_nDepth ++;

            return;
        }

        if( m_osLastTypeName == "" )
        {
            CPLError( CE_Failure, CPLE_AssertionFailed,
                      "m_osLastTypeName == \"\"");

            m_bIgnoreFeature = true;
            m_nDepthFeature = m_nDepth;
            m_nDepth ++;
            return;
        }

        if( EQUAL( pszLast, "Replace" )  &&
            ( m_osLastReplacingFID == "" || m_osLastSafeToIgnore == "" ) )
        {
            CPLError( CE_Failure, CPLE_AssertionFailed,
                      "m_osLastReplacingFID == \"\" || "
                      "m_osLastSafeToIgnore == \"\"" );

            m_bIgnoreFeature = true;
            m_nDepthFeature = m_nDepth;
            m_nDepth ++;
            return;
        }

        if( EQUAL( pszLast, "Update" )  &&
            ( m_osLastEnded == "" || m_osLastOccasion == "" ) )
        {
            CPLError( CE_Failure, CPLE_AssertionFailed,
                      "m_osLastEnded == \"\" || m_osLastOccasion == \"\"" );

            m_bIgnoreFeature = true;
            m_nDepthFeature = m_nDepth;
            m_nDepth ++;
            return;
        }

        m_bIgnoreFeature = false;

        m_poReader->PushFeature( "Delete", attrs );

        m_nDepthFeature = m_nDepth;
        m_nDepth ++;

        m_poReader->SetFeaturePropertyDirectly(
            "typeName", CPLStrdup(m_osLastTypeName) );
        m_poReader->SetFeaturePropertyDirectly( "context", CPLStrdup(pszLast) );

        if( EQUAL( pszLast, "Replace" ) )
        {
            //CPLAssert( m_osLastReplacingFID != "" );
            //CPLAssert( m_osLastSafeToIgnore != "" );
            m_poReader->SetFeaturePropertyDirectly(
                "replacedBy", CPLStrdup(m_osLastReplacingFID) );
            m_poReader->SetFeaturePropertyDirectly(
                "safeToIgnore", CPLStrdup(m_osLastSafeToIgnore) );
        }
        else if( EQUAL( pszLast, "Update" ) )
        {
            //CPLAssert( m_osLastEnded != "" );
            //CPLAssert( m_osLastOccasion != "" );
            m_poReader->SetFeaturePropertyDirectly(
                "endet", CPLStrdup(m_osLastEnded) );
            m_poReader->SetFeaturePropertyDirectly(
                "anlass", CPLStrdup(m_osLastOccasion) );
            m_osLastEnded = "";
            m_osLastOccasion = "";
        }

        return;
    }

/* -------------------------------------------------------------------- */
/*      Is it a feature?  If so push a whole new state, and return.     */
/* -------------------------------------------------------------------- */
    else if( m_poReader->IsFeatureElement( szElementName ) )
    {
        m_osLastTypeName = szElementName;

        const char* pszFilteredClassName = m_poReader->GetFilteredClassName();

        pszLast = m_poReader->GetState()->GetLastComponent();
        if( pszLast != NULL && EQUAL(pszLast,"Replace") )
        {
            XMLCh  Name[100];

            tr_strcpy( Name, "gml:id" );
            int nIndex = attrs.getIndex( Name );

            if( nIndex == -1 || m_osLastReplacingFID !="" )
            {
                CPLError( CE_Failure, CPLE_AssertionFailed,
                          "nIndex == -1 || m_osLastReplacingFID !=\"\"" );

                m_bIgnoreFeature = true;
                m_nDepthFeature = m_nDepth;
                m_nDepth ++;

                return;
            }

            // Capture "gml:id" attribute as part of the property value -
            // primarily this is for the wfsext:Replace operation's attribute.
            char *pszReplacingFID = tr_strdup( attrs.getValue( nIndex ) );
            m_osLastReplacingFID = pszReplacingFID;
            CPLFree( pszReplacingFID );

#ifdef DEBUG_VERBOSE
            CPLDebug( "NAS", "%*s### Replace typeName=%s replacedBy=%s",
                      m_nDepth, "", m_osLastTypeName.c_str(),
                      m_osLastReplacingFID.c_str() );
#endif
        }

        if ( pszFilteredClassName != NULL &&
             strcmp(szElementName, pszFilteredClassName) != 0 )
        {
            m_bIgnoreFeature = true;
            m_nDepthFeature = m_nDepth;
            m_nDepth ++;

            return;
        }

        m_bIgnoreFeature = false;

        m_poReader->PushFeature( szElementName, attrs );

        m_nDepthFeature = m_nDepth;
        m_nDepth ++;

        return;
    }

/* -------------------------------------------------------------------- */
/*      If it is the wfs:Delete or wfs:Update element, then remember    */
/*      the typeName attribute so we can assign it to the feature that  */
/*      will be produced when we process the Filter element.            */
/* -------------------------------------------------------------------- */
    else if( EQUAL(szElementName,"Delete") || EQUAL(szElementName,"Update") )
    {
        XMLCh  Name[100];

        tr_strcpy( Name, "typeName" );
        int nIndex = attrs.getIndex( Name );

        if( nIndex != -1 )
        {
            char *pszTypeName = tr_strdup( attrs.getValue( nIndex ) );
            m_osLastTypeName = pszTypeName;
            CPLFree( pszTypeName );
        }

        m_osLastSafeToIgnore = "";
        m_osLastReplacingFID = "";

        if( EQUAL(szElementName,"Update") )
        {
            m_bInUpdate = true;
        }
    }

    else if ( m_bInUpdate && EQUAL(szElementName, "Property") )
    {
        m_bInUpdateProperty = true;
    }

    else if ( m_bInUpdateProperty && ( EQUAL(szElementName, "Name" ) ||
                                       EQUAL(szElementName, "Value" ) ) )
    {
        // collect attribute name or value
        CPLFree( m_pszCurField );
        m_pszCurField = CPLStrdup("");
    }

/* -------------------------------------------------------------------- */
/*      If it is the wfsext:Replace element, then remember the          */
/*      safeToIgnore attribute so we can assign it to the feature       */
/*      that will be produced when we process the Filter element.       */
/* -------------------------------------------------------------------- */
    else if( EQUAL(szElementName,"Replace") )
    {
        XMLCh  Name[100];

        tr_strcpy( Name, "safeToIgnore" );
        int nIndex = attrs.getIndex( Name );

        if( nIndex != -1 )
        {
            char *pszSafeToIgnore = tr_strdup( attrs.getValue( nIndex ) );
            m_osLastSafeToIgnore = pszSafeToIgnore;
            CPLFree( pszSafeToIgnore );
        }
        else
        {
            CPLError( CE_Warning, CPLE_AppDefined,
                      "NAS: safeToIgnore attribute missing" );
            m_osLastSafeToIgnore = "false";
        }

        m_osLastReplacingFID = "";
    }

/* -------------------------------------------------------------------- */
/*      If it is (or at least potentially is) a simple attribute,       */
/*      then start collecting it.                                       */
/* -------------------------------------------------------------------- */
    else if( m_poReader->IsAttributeElement( szElementName ) )
    {
        CPLFree( m_pszCurField );
        m_pszCurField = CPLStrdup("");

        // Capture href as OB property.
        m_poReader->CheckForRelations( szElementName, attrs, &m_pszCurField );

        // Capture "fid" attribute as part of the property value -
        // primarily this is for wfs:Delete operation's FeatureId attribute.
        if( EQUAL(szElementName,"FeatureId") )
            m_poReader->CheckForFID( attrs, &m_pszCurField );
    }

/* -------------------------------------------------------------------- */
/*      Push the element onto the current state's path.                 */
/* -------------------------------------------------------------------- */
    poState->PushPath( szElementName );

    m_nDepth ++;
}
OGRErr GMLHandler::startElement(const char *pszName, void* attr )

{
    GMLReadState *poState = m_poReader->GetState();

    int nLNLenBytes = strlen(pszName);

/* -------------------------------------------------------------------- */
/*      If we are in the midst of collecting a feature attribute        */
/*      value, then this must be a complex attribute which we don't     */
/*      try to collect for now, so just terminate the field             */
/*      collection.                                                     */
/* -------------------------------------------------------------------- */
    if( m_pszCurField != NULL )
    {
        CPLFree( m_pszCurField );
        m_pszCurField = NULL;
    }

/* -------------------------------------------------------------------- */
/*      If we are collecting geometry, or if we determine this is a     */
/*      geometry element then append to the geometry info.              */
/* -------------------------------------------------------------------- */
    if( m_pszGeometry != NULL 
        || IsGeometryElement( pszName ) )
    {
        /* should save attributes too! */

        if( m_pszGeometry == NULL )
            m_nGeometryDepth = poState->m_nPathLength;
        
        char* pszAttributes = GetAttributes(attr);

        if( m_nGeomLen + nLNLenBytes + 4 + strlen( pszAttributes ) >
            m_nGeomAlloc )
        {
            m_nGeomAlloc = (int) (m_nGeomAlloc * 1.3 + nLNLenBytes + 1000 +
                                  strlen( pszAttributes ));
            char* pszNewGeometry = (char *) 
                VSIRealloc( m_pszGeometry, m_nGeomAlloc);
            if (pszNewGeometry == NULL)
            {
                CPLFree(pszAttributes);
                return CE_Failure;
            }
            m_pszGeometry = pszNewGeometry;
        }

        strcpy( m_pszGeometry+m_nGeomLen++, "<" );
        strcpy( m_pszGeometry+m_nGeomLen, pszName );
        m_nGeomLen += nLNLenBytes;
        /* saving attributes */
        strcat( m_pszGeometry + m_nGeomLen, pszAttributes );
        m_nGeomLen += strlen( pszAttributes );
        CPLFree(pszAttributes);
        strcat( m_pszGeometry + (m_nGeomLen++), ">" );
    }
    
/* -------------------------------------------------------------------- */
/*      Is it a feature?  If so push a whole new state, and return.     */
/* -------------------------------------------------------------------- */
    else if( m_poReader->IsFeatureElement( pszName ) )
    {
        char* pszFID = GetFID(attr);

        m_poReader->PushFeature( pszName, pszFID);

        CPLFree(pszFID);

        m_nDepthFeature = m_nDepth;
        m_nDepth ++;

        return CE_None;
    }

/* -------------------------------------------------------------------- */
/*      If it is (or at least potentially is) a simple attribute,       */
/*      then start collecting it.                                       */
/* -------------------------------------------------------------------- */
    else if( m_poReader->IsAttributeElement( pszName ) )
    {
        CPLFree( m_pszCurField );
        m_pszCurField = CPLStrdup("");
    }

/* -------------------------------------------------------------------- */
/*      Push the element onto the current state's path.                 */
/* -------------------------------------------------------------------- */
    poState->PushPath( pszName );

    m_nDepth ++;

    return CE_None;
}
OGRErr GMLHandler::startElement(const char *pszName, void* attr )

{
    GMLReadState *poState = m_poReader->GetState();

    if (m_bIgnoreFeature && m_nDepth >= m_nDepthFeature)
    {
        m_nDepth ++;
        return CE_None;
    }

    if ( m_nDepth == 0 )
    {
        if (strcmp(pszName, "CityModel") == 0 )
        {
            m_bIsCityGML = TRUE;
        }
        else if (strcmp(pszName, "AIXMBasicMessage") == 0)
        {
            m_bIsAIXM = m_bReportHref = TRUE;
        }
    }
    else if ( m_nDepth == 2 && m_bInBoundedBy )
    {
        if ( strcmp(pszName, "Envelope") == 0 )
        {
            char* pszGlobalSRSName = GetAttributeValue(attr, "srsName");
            if (pszGlobalSRSName != NULL &&
                strncmp(pszGlobalSRSName, "EPSG:", 5) == 0 &&
                CSLTestBoolean(CPLGetConfigOption("GML_CONSIDER_EPSG_AS_URN", "NO")))
            {
                char* pszNew = CPLStrdup(CPLSPrintf("urn:ogc:def:crs:EPSG::%s", pszGlobalSRSName+5));
                CPLFree(pszGlobalSRSName);
                pszGlobalSRSName = pszNew;
            }
            m_poReader->SetGlobalSRSName(pszGlobalSRSName);
            CPLFree(pszGlobalSRSName);
        }
    }

/* -------------------------------------------------------------------- */
/*      If we are in the midst of collecting a feature attribute        */
/*      value, then this must be a complex attribute which we don't     */
/*      try to collect for now, so just terminate the field             */
/*      collection.                                                     */
/* -------------------------------------------------------------------- */
    if( m_pszCurField != NULL )
    {
        CPLFree( m_pszCurField );
        m_pszCurField = NULL;
    }

    if ( m_bInCityGMLGenericAttr )
    {
        if( strcmp(pszName, "value") == 0 )
        {
            CPLFree( m_pszCurField );
            m_pszCurField = CPLStrdup("");
        }
    }

/* -------------------------------------------------------------------- */
/*      If we are collecting geometry, or if we determine this is a     */
/*      geometry element then append to the geometry info.              */
/* -------------------------------------------------------------------- */
    else if( poState->m_poFeature != NULL &&
             (m_pszGeometry != NULL
              || IsGeometryElement( pszName )
              || (m_bIsAIXM && strcmp( pszName, "ElevatedPoint") == 0)) )
    {
        int bReadGeometry;

        if( m_pszGeometry == NULL )
        {
            /* If the <GeometryElementPath> is defined in the .gfs, use it */
            /* to read the appropriate geometry element */
            const char* pszGeometryElement = (poState->m_poFeature) ?
                    poState->m_poFeature->GetClass()->GetGeometryElement() : NULL;
            if (pszGeometryElement != NULL)
                bReadGeometry = strcmp(poState->m_pszPath, pszGeometryElement) == 0;
            else
            {
                /* AIXM special case: for RouteSegment, we only want to read Curve geometries */
                /* not 'start' and 'end' geometries */
                if (m_bIsAIXM &&
                    strcmp(poState->m_poFeature->GetClass()->GetName(), "RouteSegment") == 0)
                    bReadGeometry = strcmp( pszName, "Curve") == 0;
                else
                    bReadGeometry = TRUE;
            }
            CPLAssert(m_nGeometryDepth == 0);
            m_nGeometryDepth = m_nDepth;
        }
        else
            bReadGeometry = TRUE;

        if (bReadGeometry)
        {
            char* pszAttributes = GetAttributes(attr);
            size_t nLNLenBytes = strlen(pszName);

            /* Some CityGML lack a srsDimension="3" in posList, such as in */
            /* http://www.citygml.org/fileadmin/count.php?f=fileadmin%2Fcitygml%2Fdocs%2FFrankfurt_Street_Setting_LOD3.zip */
            /* So we have to add it manually */
            if (m_bIsCityGML && strcmp(pszName, "posList") == 0 &&
                strstr(pszAttributes, "srsDimension") == NULL)
            {
                CPLFree(pszAttributes);
                pszAttributes = CPLStrdup(" srsDimension=\"3\"");
            }

            if( m_nGeomLen + nLNLenBytes + 4 + strlen( pszAttributes ) >
                m_nGeomAlloc )
            {
                m_nGeomAlloc = (size_t) (m_nGeomAlloc * 1.3 + nLNLenBytes + 1000 +
                                    strlen( pszAttributes ));
                char* pszNewGeometry = (char *)
                    VSIRealloc( m_pszGeometry, m_nGeomAlloc);
                if (pszNewGeometry == NULL)
                {
                    CPLFree(pszAttributes);
                    return CE_Failure;
                }
                m_pszGeometry = pszNewGeometry;
            }

            strcpy( m_pszGeometry+m_nGeomLen++, "<" );
            strcpy( m_pszGeometry+m_nGeomLen, pszName );
            m_nGeomLen += nLNLenBytes;
            /* saving attributes */
            strcat( m_pszGeometry + m_nGeomLen, pszAttributes );
            m_nGeomLen += strlen( pszAttributes );
            CPLFree(pszAttributes);
            strcat( m_pszGeometry + (m_nGeomLen++), ">" );
        }
    }

    else if (m_nGeometryDepth != 0 && m_nDepth > m_nGeometryDepth)
    {
        ;
    }

    else if( m_bInBoundedBy)
    {
        ;
    }

/* -------------------------------------------------------------------- */
/*      Is it a feature?  If so push a whole new state, and return.     */
/* -------------------------------------------------------------------- */
    else if( m_nDepthFeature == 0 &&
             m_poReader->IsFeatureElement( pszName ) )
    {
        const char* pszFilteredClassName = m_poReader->GetFilteredClassName();
        if ( pszFilteredClassName != NULL &&
             strcmp(pszName, pszFilteredClassName) != 0 )
        {
            m_bIgnoreFeature = TRUE;
            m_nDepthFeature = m_nDepth;
            m_nDepth ++;

            return CE_None;
        }

        m_bIgnoreFeature = FALSE;

        char* pszFID = GetFID(attr);

        m_poReader->PushFeature( pszName, pszFID);

        CPLFree(pszFID);

        m_nDepthFeature = m_nDepth;
        m_nDepth ++;

        return CE_None;
    }

    else if( strcmp(pszName, "boundedBy") == 0 )
    {
        m_bInBoundedBy = TRUE;
        m_inBoundedByDepth = m_nDepth;
    }

/* -------------------------------------------------------------------- */
/*      Is it a CityGML generic attribute ?                             */
/* -------------------------------------------------------------------- */
    else if( m_poReader->IsCityGMLGenericAttributeElement( pszName, attr ) )
    {
        m_bInCityGMLGenericAttr = TRUE;
        CPLFree(m_pszCityGMLGenericAttrName);
        m_pszCityGMLGenericAttrName = GetAttributeValue(attr, "name");
        m_inCityGMLGenericAttrDepth = m_nDepth;
    }

/* -------------------------------------------------------------------- */
/*      If it is (or at least potentially is) a simple attribute,       */
/*      then start collecting it.                                       */
/* -------------------------------------------------------------------- */
    else if( m_poReader->IsAttributeElement( pszName ) )
    {
        CPLFree( m_pszCurField );
        m_pszCurField = CPLStrdup("");
        if (m_bReportHref)
        {
            CPLFree(m_pszHref);
            m_pszHref = GetAttributeValue(attr, "xlink:href");
        }
        CPLFree(m_pszUom);
        m_pszUom = GetAttributeValue(attr, "uom");
        CPLFree(m_pszValue);
        m_pszValue = GetAttributeValue(attr, "value");
    }
    else if( m_bReportHref && m_poReader->IsAttributeElement( CPLSPrintf("%s_href", pszName ) ) )
    {
        CPLFree( m_pszCurField );
        m_pszCurField = CPLStrdup("");
        CPLFree(m_pszHref);
        m_pszHref = GetAttributeValue(attr, "xlink:href");
    }

/* -------------------------------------------------------------------- */
/*      Push the element onto the current state's path.                 */
/* -------------------------------------------------------------------- */
    poState->PushPath( pszName );

    m_nDepth ++;

    return CE_None;
}
Exemple #4
0
OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenName, void* attr )
{
    /* Reset flag */
    m_bInCurField = FALSE;

    GMLReadState *poState = m_poReader->GetState();

/* -------------------------------------------------------------------- */
/*      If we are collecting geometry, or if we determine this is a     */
/*      geometry element then append to the geometry info.              */
/* -------------------------------------------------------------------- */
    if( IsGeometryElement( pszName ) )
    {
        int bReadGeometry;

        /* If the <GeometryElementPath> is defined in the .gfs, use it */
        /* to read the appropriate geometry element */
        const char* pszGeometryElement = poState->m_poFeature->GetClass()->GetGeometryElement();
        if (pszGeometryElement != NULL)
            bReadGeometry = strcmp(poState->osPath.c_str(), pszGeometryElement) == 0;
        else
        {
            /* AIXM special case: for RouteSegment, we only want to read Curve geometries */
            /* not 'start' and 'end' geometries */
            if (m_bIsAIXM &&
                strcmp(poState->m_poFeature->GetClass()->GetName(), "RouteSegment") == 0)
                bReadGeometry = strcmp( pszName, "Curve") == 0;
            else
                bReadGeometry = TRUE;
        }
        if (bReadGeometry)
        {
            m_nGeometryDepth = m_nDepth;

            CPLAssert(apsXMLNode.size() == 0);

            NodeLastChild sNodeLastChild;
            sNodeLastChild.psNode = NULL;
            sNodeLastChild.psLastChild = NULL;
            apsXMLNode.push_back(sNodeLastChild);

            PUSH_STATE(STATE_GEOMETRY);

            return startElementGeometry(pszName, nLenName, attr);
        }
    }


    else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
    {
        m_inBoundedByDepth = m_nDepth;

        PUSH_STATE(STATE_BOUNDED_BY);

        return OGRERR_NONE;
    }

/* -------------------------------------------------------------------- */
/*      Is it a CityGML generic attribute ?                             */
/* -------------------------------------------------------------------- */
    else if( m_bIsCityGML &&
             m_poReader->IsCityGMLGenericAttributeElement( pszName, attr ) )
    {
        CPLFree(m_pszCityGMLGenericAttrName);
        m_pszCityGMLGenericAttrName = GetAttributeValue(attr, "name");
        m_inCityGMLGenericAttrDepth = m_nDepth;

        PUSH_STATE(STATE_CITYGML_ATTRIBUTE);

        return OGRERR_NONE;
    }

/* -------------------------------------------------------------------- */
/*      If it is (or at least potentially is) a simple attribute,       */
/*      then start collecting it.                                       */
/* -------------------------------------------------------------------- */
    else if( (m_nAttributeIndex =
                m_poReader->GetAttributeElementIndex( pszName, nLenName )) != -1 )
    {
        if(m_pszCurField)
        {
            CPLFree(m_pszCurField);
            m_pszCurField = NULL;
            m_nCurFieldLen = m_nCurFieldAlloc = 0;
        }
        m_bInCurField = TRUE;
        if (m_bReportHref)
        {
            CPLFree(m_pszHref);
            m_pszHref = GetAttributeValue(attr, "xlink:href");
        }
        CPLFree(m_pszUom);
        m_pszUom = GetAttributeValue(attr, "uom");
        CPLFree(m_pszValue);
        m_pszValue = GetAttributeValue(attr, "value");

        if (stateStack[nStackDepth] != STATE_PROPERTY)
        {
            m_nAttributeDepth = m_nDepth;
            PUSH_STATE(STATE_PROPERTY);
        }

    }
    else if( m_bReportHref && (m_nAttributeIndex =
                m_poReader->GetAttributeElementIndex( CPLSPrintf("%s_href", pszName ),
                                                      nLenName + 5 )) != -1 )
    {
        if(m_pszCurField)
        {
            CPLFree(m_pszCurField);
            m_pszCurField = NULL;
            m_nCurFieldLen = m_nCurFieldAlloc = 0;
        }
        m_bInCurField = TRUE;
        CPLFree(m_pszHref);
        m_pszHref = GetAttributeValue(attr, "xlink:href");

        if (stateStack[nStackDepth] != STATE_PROPERTY)
        {
            m_nAttributeDepth = m_nDepth;
            PUSH_STATE(STATE_PROPERTY);
        }
    }

    poState->PushPath( pszName, nLenName );

    return OGRERR_NONE;
}