用于组合子元素的XSLT多文档输出

时间:2012-11-15 19:25:43

标签: xml xslt split messages composition

我有一个命令,其中包含需要复制的消息和正文。像这样:

<message>
 <body>
  <command name="1"/>
  <command name="2"/>
 </body>
</message>

我想要的是:

 <message>
 <body>
  <command name="1"/>
 </body>
</message>

<message>
 <body>
   <command name="2"/>
 </body>
</message>

我正在使用以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
    <xsl:variable name="items" select="/message/body/*"/>
    <xsl:for-each select="$items">
        <xsl:result-document href="section{position()}.xml">
            <xsl:copy-of select="../../.[position()]"/>
        </xsl:result-document>
    </xsl:for-each>
</xsl:template>

一些说明:name属性不是位置属性,因此它可以变化。命令名称未知,可能会有所不同。命令本身就是节点,可以包含元素。

基于Dabbler的代码,我能够生成这个,它成功地解析了以下内容:

<message>
<body>
 <commandA num="1"/>
 <commandB num="5"/>
 <commandC num="25">
    <subCommandT />
 </commandC>
</body>
</message>

进入

<message>
 <body>
  <commandA num="1"/>
 </body> 
</message>

<message>
 <body>
  <commandB num="5"/>
 </body>
</message>

<message>
<body>
<commandC num="25">
      <subCommandT />
 </commandC>
</body>
</message>

以下是代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
    <xsl:for-each select="/message/body/*">
        <xsl:apply-templates select="/*">
            <xsl:with-param name="CmdId" select="generate-id(.)" tunnel="yes"/>
            <xsl:with-param name="CmdPosition" select="position()" tunnel="yes"/>
        </xsl:apply-templates>
    </xsl:for-each>
</xsl:template>
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="message">
    <xsl:param name="CmdId" as="xs:string" tunnel="yes"/>
    <xsl:param name="CmdPosition" as="xs:integer" tunnel="yes"/>
    <xsl:result-document href="section{$CmdPosition}.xml">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:result-document>
</xsl:template>
<xsl:template match="body/*">
    <xsl:param name="CmdId" as="xs:string" tunnel="yes"/>
    <xsl:if test="generate-id(.) = $CmdId">
        <xsl:copy-of select="."/>
    </xsl:if>
</xsl:template>

谢谢Dabbler!

以下是原始命令的示例:

<?xml version="1.0" encoding="UTF-8"?>
<tst:Message xmlns:tst="http://www.someschema.com/v1.4" xmlns:pc="http://www.someotherschema.com/v1.5">
<tst:Body tst:hostId="1" tst:machineId="77.D2" tst:dateTimeSent="2012-07-11T15:30:46">
    <tst:commandOption tst:deviceId="1" tst:dateTime="2012-07-11T15:30:46" tst:commandId="1" tst:sessionType="response" tst:sessionId="28" >
        <tst:commandOptionAck tst:transactionId="12" tst:configurationId="3148"/>
    </tst:commandOption>
    <tst:commandOption tst:deviceId="1" tst:dateTime="2012-07-11T15:30:48" tst:commandId="2" tst:sessionType="response" tst:sessionId="29" >
        <tst:commandOptionAck tst:transactionId="13" tst:configurationId="3149"/>
    </tst:commandOption>
    <tst:commandOption tst:deviceId="1" tst:dateTime="2012-07-11T15:30:50" tst:commandId="3" tst:sessionType="response" tst:sessionId="30" >
        <tst:commandOptionAck tst:transactionId="14" />
    </tst:commandOption>
    <pc:pContext pc:deviceId="1" pc:dateTime="2012-07-11T15:24:17" pc:commandId="4" pc:sessionId="47146">
        <pc:Exit pc:transactionId="3116380"/>
    </pc:pContext>
</tst:Body>

2 个答案:

答案 0 :(得分:3)

这很简单(一个模板,只有几行代码):

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pDest" select="'file:///c:/temp/delete/'"/>

 <xsl:template match="*[starts-with(name(), 'command')]">
    <xsl:result-document href="{$pDest}section{position()}.xml">
        <message>
            <body>
             <xsl:copy-of select="."/>
            </body>
        </message>
    </xsl:result-document>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<message>
    <body>
        <commandA num="1"/>
        <commandB num="5"/>
        <commandC num="25">
            <subCommandT />
        </commandC>
    </body>
</message>

创建了三个XML文件

C:\ TEMP \删除\ section1.xml:

<message>
   <body>
      <commandA num="1"/>
   </body>
</message>

C:\ TEMP \删除\ section2.xml:

<message>
   <body>
      <commandB num="5"/>
   </body>
</message>

C:\ TEMP \删除\ section3.xml

<message>
   <body>
      <commandC num="25">
         <subCommandT/>
      </commandC>
   </body>
</message>

<强>更新

OP现在提供了他的“真正的”源XML文档:

<tst:Message xmlns:tst="http://www.someschema.com/v1.4"
 xmlns:pc="http://www.someotherschema.com/v1.5">
<tst:Body tst:hostId="1" tst:machineId="77.D2"
          tst:dateTimeSent="2012-07-11T15:30:46">
    <tst:commandOption tst:deviceId="1"
                       tst:dateTime="2012-07-11T15:30:46"
                       tst:commandId="1"
                       tst:sessionType="response"
                       tst:sessionId="28" >
        <tst:commandOptionAck tst:transactionId="12"
                              tst:configurationId="3148"/>
    </tst:commandOption>
    <tst:commandOption tst:deviceId="1"
                       tst:dateTime="2012-07-11T15:30:48"
                       tst:commandId="2"
                       tst:sessionType="response"
                       tst:sessionId="29" >
        <tst:commandOptionAck tst:transactionId="13"
                              tst:configurationId="3149"/>
    </tst:commandOption>
    <tst:commandOption tst:deviceId="1"
                       tst:dateTime="2012-07-11T15:30:50"
                       tst:commandId="3"
                       tst:sessionType="response"
                       tst:sessionId="30" >
        <tst:commandOptionAck tst:transactionId="14" />
    </tst:commandOption>
    <pc:pContext pc:deviceId="1" pc:dateTime="2012-07-11T15:24:17"
                pc:commandId="4" pc:sessionId="47146">
        <pc:Exit pc:transactionId="3116380"/>
    </pc:pContext>
</tst:Body>
</tst:Message>

我们使用与上面相同的转换,只更改用于名称开头的字符串

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pDest" select="'file:///c:/temp/delete/'"/>

 <xsl:template match="*[starts-with(name(), 'tst:commandOption')]">
    <xsl:result-document href="{$pDest}section{position()}.xml">
        <message>
            <body>
             <xsl:copy-of select="."/>
            </body>
        </message>
    </xsl:result-document>
 </xsl:template>
</xsl:stylesheet>

结果是创建了这三个文件

C:\ TEMP \删除\ section1.xml

<message>
   <body>
      <tst:commandOption xmlns:tst="http://www.someschema.com/v1.4"
                         xmlns:pc="http://www.someotherschema.com/v1.5"
                         tst:deviceId="1"
                         tst:dateTime="2012-07-11T15:30:46"
                         tst:commandId="1"
                         tst:sessionType="response"
                         tst:sessionId="28">
         <tst:commandOptionAck tst:transactionId="12" tst:configurationId="3148"/>
      </tst:commandOption>
   </body>
</message>

C:\ TEMP \删除\ section2.xml

<message>
   <body>
      <tst:commandOption xmlns:tst="http://www.someschema.com/v1.4"
                         xmlns:pc="http://www.someotherschema.com/v1.5"
                         tst:deviceId="1"
                         tst:dateTime="2012-07-11T15:30:48"
                         tst:commandId="2"
                         tst:sessionType="response"
                         tst:sessionId="29">
         <tst:commandOptionAck tst:transactionId="13" tst:configurationId="3149"/>
      </tst:commandOption>
   </body>
</message>

C:\ TEMP \删除\ section3.xml

<message>
   <body>
      <tst:commandOption xmlns:tst="http://www.someschema.com/v1.4"
                         xmlns:pc="http://www.someotherschema.com/v1.5"
                         tst:deviceId="1"
                         tst:dateTime="2012-07-11T15:30:50"
                         tst:commandId="3"
                         tst:sessionType="response"
                         tst:sessionId="30">
         <tst:commandOptionAck tst:transactionId="14"/>
      </tst:commandOption>
   </body>
</message>

答案 1 :(得分:0)

可能有更好的方法,但这有效:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

   <xsl:template match="/">
      <xsl:for-each select="/message/body/*">
         <xsl:apply-templates select="/*">
            <xsl:with-param name="CmdNum" select="position()" tunnel="yes"/>
         </xsl:apply-templates>
      </xsl:for-each>
   </xsl:template>

   <xsl:template match="*|@*">
      <xsl:copy>
         <xsl:apply-templates/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="message">
      <xsl:param name="CmdNum" as="xs:integer" tunnel="yes"/>

      <xsl:result-document href="section{$CmdNum}.xml">
         <xsl:copy>
            <xsl:apply-templates/>
         </xsl:copy>
      </xsl:result-document>
   </xsl:template>

   <xsl:template match="command">
      <xsl:param name="CmdNum" as="xs:integer" tunnel="yes"/>

      <xsl:if test="@name = $CmdNum">
         <xsl:copy-of select="."/>
      </xsl:if>
   </xsl:template>
</xsl:stylesheet>

代码的问题在于,过滤器应用于message元素而不是command元素。