如何正确地将数据从两个 SAS 数据集导出到一个 XML 数据文件?

How to properly export data from two SAS datasets to one XML data file?

将多个(两个或更多)SAS 数据集(数据集 1、数据集 2)导出到一个 XML 数据文件并同时引用不同的 table 的正确方法是什么在 XML地图中 ?

执行以下命令时效果很好:

filename xmlout 'path\to\file\want.xml';
libname xmlout xmlv2 xmltype=xmlmap xmlmap='path\to\file\XMLmap.map';

data xmlout.dim;
set work.have_dim;
run;

我从另一个 SAS table 获取数据以导出到 header(ID 和时间如 .map 中所示)。 然后我会修改 .map 为:

<OUTPUT> 
   <TABLEREF name="dim" /> 
   <TABLEREF name="header" />
</OUTPUT>

并执行以下代码:

data xmlout.header;
    set work.have_header;
run;

但是,我无法将 TABLEREF 添加到 header table,因为它在文档中指定:TABLEREF= specifies the name of the table in the XMLMap to be exported. The name must be unique in the XMLMap definition, and the name must be a valid SAS name, which can be up to 32 characters.(参见 XML LIBNAME 引擎 )

所以我的问题是,如果我不能使用不同的 TABLEREF,如何将这两个 SAS table 导出到同一个 XML 文件中? 在某些时候,我想使用一个数据步骤,我只需将两个 table 设置在一起,并且只在 .map 中使用一个 TABLEREF ,如下所示:

data aggregated;
   set have_dim have_header;
run;

但是,我怎样才能将一些变量重定向到 header table(ID 和时间)以及 dim table 中的其他变量XML输出?

所需的 XML output 将是:

<?xml version="1.0" encoding="UTF-8"?>
<ns2:message xmlns:ns2="http://www.someurl/common/vo/message" xmlns:ns3="http://www.someurl/common/vo/cube">
  <ns2:header>
      <ns2:ID>1234</ns2:ID> 
      <ns2:time>2021-01-19T09:20:47</ns2:time> <!-- the time of the day --> 
  </ns2:header>
  <ns2:content>
      <ns2:dataSegment id="OBSERVATION">
            <ns2:cube id="ID_CODE">
                <ns3:obs>
                    <ns3:dim name="CODE" value="ABC123" />
                    <ns3:dim name="VAR" value="VAR1"/>
                    <ns3:dim name="VALUE" value="Y"/>       
                    <ns3:dim name="DATE" value="2021-01-01T00:00:00" />
                </ns3:obs>
            </ns2:cube>
            <ns2:cube id="ID_CODE">
                <ns3:obs>
                    <ns3:dim name="CODE" value="DEF456" />
                    <ns3:dim name="VAR" value="VAR2"/>
                    <ns3:dim name="VALUE" value="N"/>       
                    <ns3:dim name="DATE" value="2021-01-01T00:00:00" />
                </ns3:obs>
            </ns2:cube>
        </ns2:dataSegment>
  </ns2:content>
</ns2:message>

为了举例,我只显示了 2 个观察结果。尽管如此,可能会有超过 100 万次观察。

编辑:可重现示例:

SAS Code:

data have_header;
ID = 1234;
time = datetime();
run;

data have_dim;
infile datalines delimiter=",";
input CODE :. VAR :. VALUE . DATE:datetime20.;
format DATE datetime20.;
datalines;
ABC1,VAR1,Y,31DEC2020:00:00:00
ABC2,VAR2,N,31DEC2020:00:00:00
;
run;

filename dim'path\to\file\dim.xml';
libname dim xmlv2 xmltype=xmlmap xmlmap='path\to\file\map_dim.map';

data dim.dim;
set have_dim;
run;

filename header 'path\to\file\header.xml';
libname header xmlv2 xmltype=xmlmap xmlmap='path\to\file\map_header.map';

data header.header;
set have_header;
run;

libname dim clear;
libname header clear;

*** COMBINE ALL XML FILES;
proc xsl 
   in  = "path\to\file\header.xml"
   xsl = "path\to\file\script.xsl"
   out = "path\to\file\final_output.xml";
run;

XML.map 暗淡:

<?xml version="1.0" encoding="UTF-8"?>
<!-- ############################################################ -->
<!-- 2021-01-19T08:41:21 -->
<!-- SAS XML Libname Engine Map -->
<!-- Generated by XML Mapper, 904300.0.0.20150204190000_v940m3 -->
<!-- ############################################################ -->
<!-- ###  Validation report                                   ### -->
<!-- ############################################################ -->
<!-- XMLMap validation completed successfully. -->
<!-- ############################################################ -->
<SXLEMAP name="AUTO_GEN" version="2.1">

    <NAMESPACES count="2">
        <NS id="1" prefix="ns2">http://www.someurl/common/vo/message</NS>
        <NS id="2" prefix="ns3">http://www.someurl/common/vo/cube</NS>
    </NAMESPACES>
    
    <OUTPUT>
        <TABLEREF name="dim" />
    </OUTPUT>
    
    <!-- ############################################################ -->
    <TABLE description="message" name="message">
        <TABLE-PATH syntax="XPathENR">/{1}message</TABLE-PATH>

        <COLUMN class="ORDINAL" name="message_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="header" name="header">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}header</TABLE-PATH>

        <COLUMN class="ORDINAL" name="message_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="header_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}header</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>
        
    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="content" name="content">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content</TABLE-PATH>

        <COLUMN class="ORDINAL" name="message_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="content_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="dataSegment" name="dataSegment">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment</TABLE-PATH>

        <COLUMN class="ORDINAL" name="content_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="dataSegment_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN name="dataSegment_id">
            <PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/@id</PATH>
            <TYPE>character</TYPE>
            <DATATYPE>string</DATATYPE>
            <LENGTH>11</LENGTH>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="cube" name="cube">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube</TABLE-PATH>

        <COLUMN class="ORDINAL" name="dataSegment_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="cube_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN name="cube_id">
            <PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/@id</PATH>
            <TYPE>character</TYPE>
            <DATATYPE>string</DATATYPE>
            <LENGTH>27</LENGTH>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="obs" name="obs">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs</TABLE-PATH>

        <COLUMN class="ORDINAL" name="cube_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="obs_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="dim" name="dim">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs/{2}dim</TABLE-PATH>

        <COLUMN class="ORDINAL" name="obs_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="dim_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs/{2}dim</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>
        
        <COLUMN name="CODE">
            <PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs/{2}dim/CODE</PATH>
            <TYPE>character</TYPE>
            <DATATYPE>string</DATATYPE>
            <LENGTH>8</LENGTH>
        </COLUMN>
        
        <COLUMN name="VAR">
            <PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs/{2}dim/VAR1</PATH>
            <TYPE>character</TYPE>
            <DATATYPE>string</DATATYPE>
            <LENGTH>8</LENGTH>
        </COLUMN>

        <COLUMN name="VALUE">
            <PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs/{2}dim/VALUE</PATH>
            <TYPE>character</TYPE>
            <DATATYPE>string</DATATYPE>
            <LENGTH>1</LENGTH>
        </COLUMN>
        
        <COLUMN name="DATE">
            <PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs/{2}dim/DATE</PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>datetime</DATATYPE>
            <FORMAT width="10">IS8601DA</FORMAT>
            <INFORMAT width="10">IS8601DA</INFORMAT>
        </COLUMN>

    </TABLE>

</SXLEMAP>

XML.map 对于 header:

<?xml version="1.0" encoding="UTF-8"?>
<!-- ############################################################ -->
<!-- 2021-01-19T08:41:21 -->
<!-- SAS XML Libname Engine Map -->
<!-- Generated by XML Mapper, 904300.0.0.20150204190000_v940m3 -->
<!-- ############################################################ -->
<!-- ###  Validation report                                   ### -->
<!-- ############################################################ -->
<!-- XMLMap validation completed successfully. -->
<!-- ############################################################ -->
<SXLEMAP name="AUTO_GEN" version="2.1">

    <NAMESPACES count="2">
        <NS id="1" prefix="ns2">http://www.someurl/common/vo/message</NS>
        <NS id="2" prefix="ns3">http://www.someurl/common/vo/cube</NS>
    </NAMESPACES>
    
    <OUTPUT>
        <TABLEREF name="header" />
    </OUTPUT>
    
    <!-- ############################################################ -->
    <TABLE description="message" name="message">
        <TABLE-PATH syntax="XPathENR">/{1}message</TABLE-PATH>

        <COLUMN class="ORDINAL" name="message_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="header" name="header">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}header</TABLE-PATH>

        <COLUMN class="ORDINAL" name="message_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="header_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}header</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN name="ID">
            <PATH syntax="XPathENR">/{1}message/{1}header/{1}ID</PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN name="time">
            <PATH syntax="XPathENR">/{1}message/{1}header/{1}time</PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>datetime</DATATYPE>
            <FORMAT width="19">IS8601DT</FORMAT>
            <INFORMAT width="19">IS8601DT</INFORMAT>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="content" name="content">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content</TABLE-PATH>

        <COLUMN class="ORDINAL" name="message_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="content_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="dataSegment" name="dataSegment">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment</TABLE-PATH>

        <COLUMN class="ORDINAL" name="content_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="dataSegment_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN name="dataSegment_id">
            <PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/@id</PATH>
            <TYPE>character</TYPE>
            <DATATYPE>string</DATATYPE>
            <LENGTH>11</LENGTH>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="cube" name="cube">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube</TABLE-PATH>

        <COLUMN class="ORDINAL" name="dataSegment_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="cube_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN name="cube_id">
            <PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/@id</PATH>
            <TYPE>character</TYPE>
            <DATATYPE>string</DATATYPE>
            <LENGTH>27</LENGTH>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="obs" name="obs">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs</TABLE-PATH>

        <COLUMN class="ORDINAL" name="cube_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="obs_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

    </TABLE>

    <!-- ############################################################ -->
    <TABLE description="dim" name="dim">
        <TABLE-PATH syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs/{2}dim</TABLE-PATH>

        <COLUMN class="ORDINAL" name="obs_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

        <COLUMN class="ORDINAL" name="dim_ORDINAL">
            <INCREMENT-PATH beginend="BEGIN" syntax="XPathENR">/{1}message/{1}content/{1}dataSegment/{1}cube/{2}obs/{2}dim</INCREMENT-PATH>
            <TYPE>numeric</TYPE>
            <DATATYPE>integer</DATATYPE>
        </COLUMN>

    </TABLE>

</SXLEMAP>

XML output for dim (dim.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!--
          SAS XML Libname Engine (SAS92XML)
          SAS XMLMap Generated Output
          Version 9.04.01M3P06242015
          Created 2021-01-19T09:20:47
      -->
<ns2:message xmlns:ns2="http://www.someurl/common/vo/message">
   <ns2:content>
      <ns2:dataSegment>
         <ns2:cube>
            <ns3:obs xmlns:ns3="http://www.someurl/common/vo/cube">
               <ns3:dim>
                  <CODE>ABC1</CODE>
                  <VAR1>VAR1</VAR1>
                  <VALUE>Y</VALUE>
                  <DATE>2020-12-31T00:00:00</DATE>
               </ns3:dim>
               <ns3:dim>
                  <CODE>ABC2</CODE>
                  <VAR1>VAR2</VAR1>
                  <VALUE>N</VALUE>
                  <DATE>2020-12-31T00:00:00</DATE>
               </ns3:dim>
            </ns3:obs>
         </ns2:cube>
      </ns2:dataSegment>
   </ns2:content>
</ns2:message>

XML output for header (header.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!--
          SAS XML Libname Engine (SAS92XML)
          SAS XMLMap Generated Output
          Version 9.04.01M3P06242015
          Created 2021-01-19T09:39:44
      -->
<ns2:message xmlns:ns2="http://www.someurl/common/vo/message">
   <ns2:header>
      <ns2:ID>1234</ns2:ID>
      <ns2:time>2021-01-19T09:39:44</ns2:time>
   </ns2:header>
</ns2:message>

期望的最终 XML 输出:

<?xml version="1.0" encoding="UTF-8"?>
<ns2:message xmlns:ns2="http://www.someurl/common/vo/message" xmlns:ns3="http://www.someurl/common/vo/cube">
  <ns2:header>
      <ns2:ID>1234</ns2:ID> 
      <ns2:time>2021-01-19T09:20:47</ns2:time> <!-- the time of the day --> 
  </ns2:header>
  <ns2:content>
      <ns2:dataSegment id="OBSERVATION">
            <ns2:cube id="ID_CODE">
                <ns3:obs>
                    <ns3:dim name="CODE" value="ABC1" />
                    <ns3:dim name="VAR" value="VAR1"/>
                    <ns3:dim name="VALUE" value="Y"/>       
                    <ns3:dim name="DATE" value="2020-12-31T00:00:00" />
                </ns3:obs>
            </ns2:cube>
            <ns2:cube id="ID_CODE">
                <ns3:obs>
                    <ns3:dim name="CODE" value="ABC2" />
                    <ns3:dim name="VAR" value="VAR2"/>
                    <ns3:dim name="VALUE" value="N"/>       
                    <ns3:dim name="DATE" value="2020-12-31T00:00:00" />
                </ns3:obs>
            </ns2:cube>
        </ns2:dataSegment>
  </ns2:content>
</ns2:message>

将 proc xls 与 Parfait 一起使用时的结果 script.xls:

<?xml version="1.0" encoding="UTF-8"?><ns2:message xmlns:ns2="http://www.someurl/common/vo/message"><ns2:header>
<ns2:ID>1234</ns2:ID>
<ns2:time>2021-01-19T09:39:44</ns2:time>
</ns2:header></ns2:message>

考虑 XSLT, the special purpose language designed to transform XML files, such as combining from different documents. SAS can run XSLT 1.0 even 2.0 using proc xsl

但是,您实际上需要两个 XSLT 转换,因为您想要的输出不完全是两个 XML 文件的堆栈,即 dim.xml 中的元素被迁移到属性。

XSLT 1(另存为.xsl文件,一个特殊的.xml文件)

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                             xmlns:ns2="http://www.someurl/common/vo/message"
                             xmlns:ns3="http://www.someurl/common/vo/cube"> 
  <xsl:output indent="yes" encoding="UTF-8"/>
  <xsl:strip-space elements="*"/>
    
  <xsl:template match="/ns2:message">
    <ns2:message xmlns:ns2="http://www.someurl/common/vo/message" xmlns:ns3="http://www.someurl/common/vo/cube"> 
         <xsl:apply-templates select="ns2:content"/>
    </ns2:message>
  </xsl:template> 
 
   <xsl:template match="ns2:content">
    <xsl:copy> 
         <xsl:apply-templates select="ns2:dataSegment"/>
    </xsl:copy>
  </xsl:template> 
  
  <xsl:template match="ns2:dataSegment">
    <xsl:copy> 
         <xsl:attribute name="id">OBSERVATION</xsl:attribute>
         <xsl:apply-templates select="*"/>
    </xsl:copy>
  </xsl:template> 
  
  <xsl:template match="ns2:cube|ns3:obs">
     <xsl:apply-templates select="*"/>
  </xsl:template> 
  
  <xsl:template match="ns3:dim">
    <ns2:cube id="ID_CODE">
      <ns3:obs> 
         <xsl:for-each select="*">  
             <ns3:dim> 
                 <xsl:attribute name="name">
                    <xsl:value-of select="name()"/>
                 </xsl:attribute>
                 <xsl:attribute name="value">
                    <xsl:value-of select="text()"/>
                 </xsl:attribute>
            </ns3:dim>
         </xsl:for-each>
      </ns3:obs>     
     </ns2:cube>
  </xsl:template> 
  
</xsl:transform>

XSLT 2 (另存为 .xsl 文件;使用带有 file:// 关键字的绝对路径引用)

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                             xmlns:ns2="http://www.someurl/common/vo/message"> 
  <xsl:output indent="yes" encoding="UTF-8"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="/ns2:message">
    <ns2:message xmlns:ns2="http://www.someurl/common/vo/message" xmlns:ns3="http://www.someurl/common/vo/cube"> 
         <!-- COPY CURRENT DATA -->
         <xsl:copy-of select="*"/>

         <!-- COMBINE ALL DATA FROM NEW dim.xml -->
         <xsl:copy-of select="document('file://absolute/path/to/new_dim.xml')/ns2:message/*" />
    </ns2:message>
  </xsl:template> 
  
</xsl:transform>

SAS (使用宏输出多个文件)

*** OUTPUT INDIVIDUAL XML FILES;
%macro output_xmls(dset);
   filename xmlout "path\to\file\&dset..xml";
   libname xmlout xmlv2 xmltype=xmlmap xmlmap='path\to\file\XMLmap.map';

   data xmlout.&dset;
      set work.&dset;
   run;

   libname xmlout clear;
%mend output_xmls;

%output_xmls(header);
%output_xmls(dim);


*** TRANSFORM RAW dim.xml;
proc xsl 
   in  = "path\to\file\dim.xml"
   xsl = "path\to\file\script_1.xsl"
   out = "path\to\file\new_dim.xml";
run;

*** COMBINE header.xml and new_dim.xml FILES;
proc xsl 
   in  = "path\to\file\header.xml"
   xsl = "path\to\file\script_2.xsl"
   out = "path\to\file\final.xml";
run;

输出

<?xml version="1.0" encoding="UTF-8"?>
<ns2:message xmlns:ns2="http://www.someurl/common/vo/message"
             xmlns:ns3="http://www.someurl/common/vo/cube">
   <ns2:header>
      <ns2:ID>1234</ns2:ID>
      <ns2:time>2021-01-19T09:39:44</ns2:time>
   </ns2:header>
   <ns2:content>
      <ns2:dataSegment id="OBSERVATION">
         <ns2:cube id="ID_CODE">
            <ns3:obs>
               <ns3:dim name="CODE" value="ABC1"/>
               <ns3:dim name="VAR1" value="VAR1"/>
               <ns3:dim name="VALUE" value="Y"/>
               <ns3:dim name="DATE" value="2020-12-31T00:00:00"/>
            </ns3:obs>
         </ns2:cube>
         <ns2:cube id="ID_CODE">
            <ns3:obs>
               <ns3:dim name="CODE" value="ABC2"/>
               <ns3:dim name="VAR1" value="VAR2"/>
               <ns3:dim name="VALUE" value="N"/>
               <ns3:dim name="DATE" value="2020-12-31T00:00:00"/>
            </ns3:obs>
         </ns2:cube>
      </ns2:dataSegment>
   </ns2:content>
</ns2:message>