繁体   English   中英

使用 SAS 合并两个 XML 文件

[英]Combine two XML files using SAS

我有两个 XML 文件( AB ),我想要 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 AB使用以下.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),则必须在INFILEFILE中指定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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM