[英]Combine two XML files using SAS
我有两个 XML 文件( A
和B
),我想要 append 形成 XML 文件C
. 基本上A
只是一个“标题”, B
是“主要”内容。
A.xml
:
<?xml version="1.0" encoding="utf-8" ?>
<!--
SAS XML Libname Engine (SAS92XML)
SAS XMLMap Generated Output
Version 9.04.01M3P06242015
Created 2021-02-18T16:52:07
-->
<ns2:message xmlns:ns2="message">
<ns2:header xmlns:ns2="message">
<ns2:ID xmlns:ns2="message">11111</ns2:ID>
<ns2:survey xmlns:ns2="message">AABB</ns2:survey>
<ns2:partner xmlns:ns2="message">ABC</ns2:partner>
<ns2:initialDate xmlns:ns2="message">2020-01-01T00:00:00.000+00:00</ns2:initialDate>
<ns2:timeProduction xmlns:ns2="message">2021-02-18T16:41:35</ns2:timeProduction>
<ns2:type xmlns:ns2="message">TYPEOFMESSAGE</ns2:type>
</ns2:header>
</ns2:message>
B.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<ns2:message xmlns:ns2="message"
xmlns:ns3="send">
<ns2:content>
<ns2:dataSegment id="OBSERVATION">
<ns2:cube id="ABCD">
<ns3:obs>
<ns3:dim name="ID" value="1"/>
<ns3:dim name="FROM" value="2021-02-17"/>
<ns3:dim name="TO" value="2021-02-19"/>
<ns3:dim name="VALUE" value="A"/>
</ns3:obs>
</ns2:cube>
</ns2:dataSegment>
</ns2:content>
</ns2:message>
C.xml (want)
:
<?xml version="1.0" encoding="UTF-8"?>
<ns2:message xmlns:ns2="message"
xmlns:ns3="send">
<ns2:header>
<ns2:ID>11111</ns2:ID>
<ns2:survey>AABB</ns2:survey>
<ns2:partner>ABC</ns2:partner>
<ns2:initialDate>2020-01-01T00:00:00.000+00:00</ns2:initialDate>
<ns2:timeProduction>2021-02-18T16:41:35</ns2:timeProduction>
<ns2:type>TYPEOFMESSAGE</ns2:type>
</ns2:header>
<ns2:content>
<ns2:dataSegment id="OBSERVATION">
<ns2:cube id="ABCD">
<ns3:obs>
<ns3:dim name="ID" value="1"/>
<ns3:dim name="FROM" value="2021-02-17"/>
<ns3:dim name="TO" value="2021-02-19"/>
<ns3:dim name="VALUE" value="A"/>
</ns3:obs>
</ns2:cube>
</ns2:dataSegment>
</ns2:content>
</ns2:message>
很长一段时间以来,我一直在使用PROC XSL
到 append A
和B
使用以下.xsl
脚本
script.xsl
:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns2="message">
<xsl:output indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/ns2:message">
<ns2:message xmlns:ns2="message" xmlns:ns3="send">
<!-- COPY CURRENT DATA -->
<xsl:copy-of select="*"/>
<!-- COMBINE ALL DATA FROM file.xml -->
<xsl:copy-of select="document('file:/path/to/file.xml')/ns2:message/*" />
</ns2:message>
</xsl:template>
</xsl:transform>
但是,我发现当B
太大(~60MB)时, PROC XSL
不会创建C
(当B
不是那么大时它可以完美地完成工作)。
SAS Code
:
proc xsl
in = 'path/to/file/A.xml'
xsl = 'path/to/file/script.xsl'
out = 'path/to/file/final.xml';
run;
日志中没有错误/警告。
SAS Log
:
MPRINT(GENERATE_XML): proc xsl
in = 'path/to/file/A.xml'
xsl = 'path/to/file/script.xsl'
out = 'path/to/file/final.xml';
MPRINT(GENERATE_XML): run;
NOTE: PROCEDURE XSL used (Total process time):
real time 19.61 seconds
cpu time 0.00 seconds
由于它是一个很小的插入,实际上附加了 8 行,我想知道是否不能通过data _null_
步骤读取B.xml
并在顶部插入(例如使用put
语句)这 8 行xml 文件?
如果所有 xml 不在一行中,可以使用data _null_;
在包含标签中读取和堆叠这两个文件的步骤。
例子:
仅文本处理。 不检查任何形式的有效性。 如果文本行长于默认值 (256),则必须在INFILE
和FILE
中指定LRECL=
filename xml_a temp;
filename xml_b temp;
filename xml_c 'c:\temp\c_wanted.xml';
* create xml a;
data _null_;
file xml_a;
input; put _infile_;
datalines4;
<?xml version="1.0" encoding="utf-8" ?>
<!--
SAS XML Libname Engine (SAS92XML)
SAS XMLMap Generated Output
Version 9.04.01M3P06242015
Created 2021-02-18T16:52:07
-->
<ns2:message xmlns:ns2="message">
<ns2:header xmlns:ns2="message">
<ns2:ID xmlns:ns2="message">11111</ns2:ID>
<ns2:survey xmlns:ns2="message">AABB</ns2:survey>
<ns2:partner xmlns:ns2="message">ABC</ns2:partner>
<ns2:initialDate xmlns:ns2="message">2020-01-01T00:00:00.000+00:00</ns2:initialDate>
<ns2:timeProduction xmlns:ns2="message">2021-02-18T16:41:35</ns2:timeProduction>
<ns2:type xmlns:ns2="message">TYPEOFMESSAGE</ns2:type>
</ns2:header>
</ns2:message>
;;;;
* create xml b;
data _null_;
file xml_b;
input; put _infile_;
datalines4;
<?xml version="1.0" encoding="UTF-8"?>
<ns2:message xmlns:ns2="message"
xmlns:ns3="send">
<ns2:content>
<ns2:dataSegment id="OBSERVATION">
<ns2:cube id="ABCD">
<ns3:obs>
<ns3:dim name="ID" value="1"/>
<ns3:dim name="FROM" value="2021-02-17"/>
<ns3:dim name="TO" value="2021-02-19"/>
<ns3:dim name="VALUE" value="A"/>
</ns3:obs>
</ns2:cube>
</ns2:dataSegment>
</ns2:content>
</ns2:message>
;;;;
* stack a and b within message send;
data _null_;
file xml_c;
put
'<?xml version="1.0" encoding="UTF-8"?>'
/ '<ns2:message xmlns:ns2="message"'
/ ' xmlns:ns3="send">'
;
put /'<!-- file a -->'/;
flag = 0;
do while (not eof_a);
infile xml_a end=eof_a;
input;
if not flag and strip(_infile_)=:'<ns2:header xmlns:ns2="message">' then flag=1;
if flag then put _infile_;
if flag and strip(_infile_)=:'</ns2:header>' then flag = 0;
end;
put /'<!-- file b -->'/;
flag = 0;
do while (not eof_b);
infile xml_b end=eof_b;
input;
if not flag and strip(_infile_)=:'<ns2:content>' then flag=1;
if flag then put _infile_;
if flag and strip(_infile_)=:'</ns2:content>' then flag = 0;
end;
put
'</ns2:message>'
;
stop;
run;
实际上,我确实在 SAS 9.4 上为 Windows(64 位/64 GB RAM)重现了该问题,但产生以下错误:
错误:java.lang.OutOfMemoryError:超出 GC 开销限制
错误:java.io.IOException:Pipe 已关闭
众所周知,XSLT 是内存密集型的,需要将所有文档保存在 memory 中以及对该树的操作。 一个人需要大约 5 倍的 memory 作为文本大小。 proc xsl
中的 SAS 可能会在内部限制 memory 对大文件的使用。
幸运的是,XSLT 是一种不需要 SAS 即可运行的行业语言。 If using SAS on Windows consider interfacing with the built-in XSLT processor, System.Xml.Xsl via a PowerShell script that you can call at command line or with SAS's X command .
Also, try reversing your operations in SAS and XSLT by redesigning the larger, B.xml
, with an append of A.xml
on top..
XSLT (另存为.xsl 以便在 PowerShell 中调用)
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns2="message">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/ns2:message">
<ns2:message xmlns:ns2="message" xmlns:ns3="send">
<!-- COMBINE ALL DATA FROM A.xml -->
<xsl:copy-of select="document('file:/path/to/A.xml')/ns2:message/*" />
<!-- COPY CURRENT DATA -->
<xsl:copy-of select="*"/>
</ns2:message>
</xsl:template>
</xsl:transform>
PowerShell (另存为.ps1文件供SAS调用)
$xslt = New-Object System.Xml.Xsl.XslCompiledTransform;
$settings = New-Object System.Xml.Xsl.XsltSettings($true, $false);
$resolver = New-Object System.Xml.XmlUrlResolver;
$xslt.Load("path/to/file/script.xsl", $settings, $resolver);
$xslt.Transform("path/to/file/B.xml",
"path/to/file/final.xml");
(上面对我来说运行得相当快,有一个 300 MB 的文件!)
SAS (是的,PowerShell window 将启动的单行)
X 'powershell -executionPolicy bypass -noexit -file "/path/to/powershell/script.ps1"';
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.