我有一个命令,其中包含需要复制的消息和正文。像这样:
<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>
答案 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
元素。