Файл карты, созданный библиотекой XMLV2
, можно изменить перед использованием libref для копирования данных в сеанс SAS.
Существует много способов обработки файла карты, сгенерированного движком (который является xml сам файл)
- XSL-преобразование (Pro c XSL)
- Кто-то (не я), хорошо разбирающийся в языке XSLT, может написать короткую программу для выполнения модификаций
- Programmati c манипулирование разобранным xml документом
- Текстовое манипулирование xml файлом
- Ручное редактирование
- Программа обработки текста
Файл карты :
- определяет, какие xml узлы должны стать столбцами набора данных
- определяет тип, длину, формат, метку и т. Д. c столбца
- определяет, какие таблицы должны быть созданы
- определяет какие таблицы должны содержать какие столбцы
В случае необходимости изменить Интерпретация механизма XMLV2 числовых c столбцов в символьные столбцы, файл карты необходимо изменить (он же преобразованный ).
<COLUMN>
узлы имеют дочерние узлы, которые на минимум, необходимо изменить
с
<TYPE>numeric</TYPE>
на
<TYPE>character</TYPE>
Соображения
Есть другие соображения, которые вам, возможно, придется учитывать при преобразовании чисел в набор символов, например:
- Является ли эта цифра c датой?
- Должно ли число отображаться сначала в его формате? ?
Пользователи SAS довольны концепцией единого «набора данных», который содержит как данные, так и метаданные (в заголовке). Для данных XML данные находятся в одном файле, а метаданные (файл карты) - в другом.
Когда экспортируются данные SAS и сохраняются только данные xml, метаданные теряются. Возврат в обратном направлении в SAS означает, что метаданные должны быть угаданы через autop.
Пример кода для "Programmati c манипулирования разобранным xml документом"
В этом примере все определения столбцов для числовых значений c заменяются символами. XPath /SXLEMAP/TABLE/COLUMN[not(@class='ORDINAL') and ./TYPE[text()='numeric']
используется для определения определений столбцов, которые будут изменены. Никаких дополнительных особых соображений не делается.
Создание xml файла данных для обработки
%macro createXmlV2(data=,folder=);
%local lib mem;
%let syslast = &data;
%let lib = %scan(&syslast,1,.);
%let mem = %scan(&syslast,2,.);
FILENAME XMLOUT "&folder./&data..xml";
LIBNAME XMLOUT XMLV2;
proc copy in=&lib out=xmlout;
select &mem;
run;
LIBNAME XMLOUT clear;
FILENAME XMLOUT clear;
%mend;
%* Something to play with;
%* Create an XMLV2 generated xml file containing the data set;
%createXmlV2 (data=sashelp.citiday, folder=/temp)
%createXmlV2 (data=sashelp.citimon, folder=/temp)
%createXmlV2 (data=sashelp.baseball, folder=/temp)
%*;
Преобразование файла автомата таким образом, чтобы числовые столбцы c стали столбцы символов
%macro prepXmlRefsFor(file=);
FILENAME XMLFILE "&file";
FILENAME MAPOUT "&file..map";
FILENAME MAPOUT2 "&file..map.transformed";
%mend;
%prepXmlRefsFor(file=/temp/sashelp.citiday.xml)
%prepXmlRefsFor(file=/temp/sashelp.baseball.xml)
%prepXmlRefsFor(file=/temp/sashelp.citimon.xml)
%*;
%* create an automap file using XMLV2 library engine;
LIBNAME XMLFILE XMLV2 XMLTYPE=XMLMAP XMLMAP=MAPOUT AUTOMAP=REPLACE ;
%* parse and rewrite the generated map file ;
%* change ALL non-ordinal, non-character COLUMN nodes to indicate character type wanted;
proc groovy;
submit
"%sysfunc(pathname(MAPOUT))"
"%sysfunc(pathname(MAPOUT2))"
"20"
;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
// get parameter from submit line;
map_in=args[0]; // the automap
map_out=args[1]; // the automap transformed
length=args[2]; // length of character value for columns previously considered numeric
// parse mapfile;
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(map_in);
xPath = XPathFactory.newInstance().newXPath();
// select the set of automap nodes that define non-ordinal, numeric columns
columns = xPath.evaluate(
"/SXLEMAP/TABLE/COLUMN" +
"[" +
"not(@class='ORDINAL')" +
" and " +
"./TYPE[text()='numeric']" +
"]", doc, XPathConstants.NODESET);
for (column in columns) {
type = xPath.evaluate("TYPE", column, XPathConstants.NODE);
dtyp = xPath.evaluate("DATATYPE", column, XPathConstants.NODE);
leng = xPath.evaluate("LENGTH", column, XPathConstants.NODE);
type.setTextContent("character");
dtyp.setTextContent("string");
if (leng == null)
column.appendChild(leng = doc.createElement("LENGTH"));
leng.setTextContent(length);
}
// rewrite mapfile with updated nodes
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(doc), new StreamResult(new File(map_out))
);
println "Programmatic transformation of mapfile completed.";
endsubmit;
quit;
* resubmit libname so libref uses transformed mapfile;
LIBNAME XMLFILE XMLV2 XMLTYPE=XMLMAP XMLMAP=MAPOUT2 AUTOMAP=REUSE;
proc copy in=xmlfile out=work;
run;
LIBNAME XMLFILE clear;
FILENAME XMLFILE clear;
FILENAME MAPOUT clear;
FILENAME MAPOUT2 clear;
Одна вещь, которая стала очевидной после изучения результата «туда-обратно», состоит в том, что xml файлы созданы с помощью XMLV2
при повторном чтении , создаст отдельные таблицы с именами столбцов для любых столбцов, которые содержат пропущенные значения. Эти таблицы должны быть объединены для воссоздания исходного набора данных.