首页 > 解决方案 > 修改 SAS XML 映射文件中的数据类型

问题描述

在 SAS 中读取 XML 数据时需要控制数据类型。使用 SAS 中的 XML libname 引擎写入和访问 XML 数据。

XML 文件:

<Test>
   <origin>YYYY</origin>
   <NumToUse>50503</NumToUse>
   <AcctNum>3-219HHJLJ</AcctNum>
   <Status>1</Status>
   <TADIG>AUSVF</TADIG>
   <LocationNumber>1234567891011</LocationNumber>
   <Phnumber>1234567890</Phnumber>
   <ReferenceNumber>0044E71146</ReferenceNumber>

地图文件:

    <COLUMN name="LocationNumber">
        <PATH syntax="XPath">/Test/LocationNumber</PATH>
        <TYPE>character</TYPE>
        <DATATYPE>string</DATATYPE>
        <LENGTH>11</LENGTH>
    </COLUMN>

    <COLUMN name="PhNumber">
        <PATH syntax="XPath">/Test/PhNumber</PATH>
        <TYPE>character</TYPE>
        <DATATYPE>string</DATATYPE>
        <LENGTH>15</LENGTH>
    </COLUMN>

    <COLUMN name="ReferenceNumber">
        <PATH syntax="XPath">/Test/ReferenceNumber</PATH>
        <TYPE>numeric</TYPE>
        <DATATYPE>double</DATATYPE>
    </COLUMN>

由于参考编号被视为数字,因此无法获得该特定列的值。它给了我

ERROR: Data contains invalid content for float datatype. Invalid content is 0044E71146

如何将数据读入 SAS 数据集?建议请

标签: sas

解决方案


您可能理解 XMLV2 引擎中内置的自动映射功能选择将 ReferenceNumber 定义为数字而不是字符,因为解析器正在检查的唯一一个值是0044E71146并且假定#E#是科学(或指数)表示法一个号码。

解决方案是让 libname 自动映射数据 xml 文件,然后更新映射文件 xml 以满足您的要求。

示例代码:

XMLV2引擎创建MAPFILE, 并Proc GROOVY用于 XML 解析和重写映射文件。

FILENAME XMLFILE "/temp/test.xml" ;
FILENAME MAPFILE "/temp/test.xml.map" ;

* parse data test.xml and write mapfile test.xml.map;
LIBNAME XMLFILE XMLV2 XMLTYPE=XMLMAP XMLMAP=MAPFILE AUTOMAP=REPLACE ;

* parse and rewrite mapfile;
* change desired column nodes to be string/character of a specified length;

proc groovy;
submit "%sysfunc(pathname(mapfile))";
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

* get parameter from submit line;

mapfile=args[0];

* parse mapfile;

doc = DocumentBuilderFactory
      .newInstance()
      .newDocumentBuilder()
      .parse(
        mapfile
      )
      ;

xPath = XPathFactory
        .newInstance()
        .newXPath()
        ;

void setCharacter(column,length) {

  * find column node and child nodes important to XMLV2 mapfile usage;

  node = xPath.evaluate("/SXLEMAP/TABLE/COLUMN[@name='"+column+"']", doc, XPathConstants.NODE);
  type = xPath.evaluate("TYPE",     node, XPathConstants.NODE);
  dtyp = xPath.evaluate("DATATYPE", node, XPathConstants.NODE);
  leng = xPath.evaluate("LENGTH",   node, XPathConstants.NODE);

  if (type != null && !type.getTextContent().equals("character")) { type.setTextContent("character") } 
  if (dtyp != null && !dtyp.getTextContent().equals("string"))    { dtyp.setTextContent("string") } 
  if (leng == null) {
    leng = doc.createElement("LENGTH");
    leng.setTextContent(length.toString());
    node.appendChild(leng);
  }
  else
  if (!length.getTextContent().equals(length.toString())) {
    leng.setTextContent(length.toString());
  }
}

// Make sure these two columns will be character, if not already

setCharacter("ReferenceNumber",25);
setCharacter("Phnumber", 20);

// rewrite mapfile with updated nodes

TransformerFactory
.newInstance()
.newTransformer()
.transform(
  new DOMSource(doc),
  new StreamResult(new File(mapfile))
);

endsubmit;
quit;

* resubmit libname so libref uses now updated mapfile;

LIBNAME XMLFILE XMLV2 XMLTYPE=XMLMAP XMLMAP=MAPFILE;

proc copy in=xmlfile out=work;
run;

注意:您可以对地图文件进行文本解析和重写,但是,地图文件可能无法满足您的“文本解析”期望的可能性很小。


推荐阅读