Pregunta

Tengo la siguiente función definida a través de PROC FCMP. El punto del código debería ser bastante obvio y relativamente sencillo. Estoy devolviendo el valor de un atributo de una línea de XHTML. Aquí está el código:

proc fcmp outlib=library.funcs.crawl;
    function getAttr(htmline $, Attribute $) $;

       /*-- Find the position of the match --*/
    Pos = index( htmline , strip( Attribute )||"=" );

       /*-- Now do something about it --*/
       if pos > 0 then do;
          Value = scan( substr( htmline, Pos + length( Attribute ) + 2), 1, '"');
       end;
       else Value = "";
       return( Value);
    endsub;
run;

No importa lo que haga con la longitud o la sentencia attrib para intentar declarar explícitamente el tipo de datos devueltos, SIEMPRE devuelve solo un máximo de 33 bytes de la cadena solicitada, independientemente de la longitud del valor de retorno real. Esto sucede sin importar qué atributo estoy buscando. El mismo código (codificado) en un paso de datos devuelve los resultados correctos, por lo que está relacionado con PROC FCMP.

Aquí está el paso de datos que estoy usando para probarlo (donde PageSource.html es cualquier archivo html que tiene atributos compatibles con xhtml - completamente citado):

data TEST;
length href $200;
infile "F:\PageSource.html";

input;

htmline = _INFILE_;

href = getAttr( htmline, "href");
x = length(href);

run;

ACTUALIZACIÓN: Esto parece funcionar correctamente después de actualizar a SAS9.2 - Versión 2

¿Fue útil?

Solución 3

Terminé dejando de usar las funciones de paso de datos definidas por FCMP. No creo que estén listos para el horario estelar. No solo no pude resolver el problema de devolución de 33 bytes, sino que comenzó a fallar regularmente SAS.

Así que volvamos a la buena tecnología (macros) de las macros. Esto funciona:

/*********************************/
/*= Macro to extract Attribute  =*/
/*= from XHTML string           =*/
/*********************************/
%macro getAttr( htmline, Attribute, NewVar );
   if index( &htmline , strip( &Attribute )||"=" ) > 0 then do;
      &NewVar = scan( substr( &htmline, index( &htmline , strip( &Attribute )||"=" ) + length( &Attribute ) + 2), 1, '"' );
   end;
%mend;

Otros consejos

En este caso, un control de puntero de entrada debería ser suficiente. Espero que esto ayude.

/* create a test input file */
data _null_;
  file "f:\pageSource.html";
  input;
  put _infile_;
cards4;
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="w3.org/StyleSheets/TR/W3C-REC.css"; type="text/css"?>
;;;;
run;

/* extract the href attribute value, if any.                          */
/* assuming that the value and the attribute name occurs in one line. */
/* and max length is 200 chars.                                       */
data one;
  infile "f:\pageSource.html" missover;
  input @("href=") href :$200.;
  href = scan(href, 1, '"'); /* unquote */
run;

/* check */
proc print data=one;
run;
/* on lst
Obs                  href
 1
 2     w3.org/StyleSheets/TR/W3C-REC.css
*/

Creo que el problema (aunque no sé por qué) está en la función de exploración: parece estar truncando la entrada de substr (). Si extrae la función substr de scan (), asigne el resultado de la función substr a una nueva variable que luego pasa a scan, parece que funciona.

Esto es lo que ejecuté:

proc fcmp outlib=work.funcs.crawl;
    function getAttr(htmline $, Attribute $) $;
    length y $200;
       /*-- Find the position of the match --*/
    Pos = index( htmline , strip( Attribute )||"=" );

       /*-- Now do something about it --*/
       if pos > 0 then do;
          y=substr( htmline, Pos + length( Attribute ) + 2);
          Value = scan( y, 1, '"');       
       end;
       else Value = "";
       return( Value);
    endsub;
run;

options cmplib=work.funcs;

data TEST;
length href $200;
infile "PageSource.html";

input;

htmline = _INFILE_;
href = getAttr( htmline, "href");
x = length(href);
run;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top