Por que a função PROC FCMP sempre retornar 33 bytes e não mais?
Pergunta
Eu tenho a seguinte função definida via PROC FCMP. O ponto do código deve ser bastante óbvio e relativamente simples. Estou retornando o valor de um atributo de uma linha de XHTML. Aqui está o 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;
Não importa o que eu faço com o comprimento ou declaração attrib para tentar declarar explicitamente o tipo de dados retornado, ele sempre retorna apenas um máximo de 33 bytes da string solicitado, independentemente de quanto tempo o valor de retorno real é. Isso acontece não importa qual atributo que estou procurando. O mesmo código (hard-coded) numa etapa de dados devolve os resultados correctos de modo que este está relacionado com PROC FCMP.
Aqui está a datastep que estou usando para testá-lo (onde PageSource.html é qualquer arquivo html que tem atributos compatíveis com XHTML - totalmente citado):
data TEST;
length href $200;
infile "F:\PageSource.html";
input;
htmline = _INFILE_;
href = getAttr( htmline, "href");
x = length(href);
run;
UPDATE: Isso parece funcionar corretamente após a atualização para o SAS9.2 - Release 2
Solução 3
acabei retirando de usar FCMP funções degrau de dados definido. Eu não acho que eles estão prontos para o horário nobre. Não só eu não poderia resolver o problema de retorno de 33 byte, mas começou regularmente bater SAS.
Então, de volta aos bons velhos (décadas), tecnologia de macros. Isso 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;
Outras dicas
Neste caso, um controle de ponteiro de entrada deve ser suficiente. espero que isso ajude.
/* 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
*/
Eu acho que o problema (embora eu não sei porque) está na função de digitalização - parece estar truncando a entrada de substr (). Se você puxar a função substr fora de varredura (), atribuir o resultado da função substr a uma nova variável que você, em seguida, passar para fazer a varredura, parece trabalho.
Aqui está o que eu corri:
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;