XSLT从XML到XML文档的转换

时间:2013-09-17 17:20:59

标签: xml spring xslt

我需要帮助才能获得正确的XSL转换,我希望源XML可以按原样复制,并对目标XML文件进行必要的更新。现在我正在尝试两件事,首先是将源复制到目标XML,其次是更新根元素的命名空间URL和版本属性。请找到下面的代码,让我知道出了什么问题,因为我只获取目标xml中的根元素,内容丢失,根元素的结束标记丢失,属性版本也没有更新。

源XML -

<soapenv:Envelope 
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:v1="http://www.abc.com/s/v1.0">
<soapenv:Header/>
<soapenv:Body>
<v1:QueryRequest version="1">
<subject>
<dataList>
<!--1 or more repetitions:-->
<dataset>
<type>company</type>
<value>abc</value>
</dataset>
<dataset>
<type>user</type>
<value>xyz</value>
</dataset>
</dataList>
</subject>
<!--Optional:-->
<testList>
<!--1 or more repetitions:-->
<criteria>
<type>test</type>
<value>972</value>
</criteria>
<criteria>
<type>test2</type>
<value>false</value>
</criteria>
</testList>
</v1:QueryRequest>
</soapenv:Body>
</soapenv:Envelope>

XSL文件: -

<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:old="http://www.abc.com/s/v1.0" exclude-result-prefixes="old">    
<xsl:output method="xml" encoding="utf-8" indent="yes"  version="1.0" />

<xsl:param name="newversion" select="2.0"> </xsl:param>
<!-- replace namespace of elements in old namespace -->

<xsl:template match="old:*">
<xsl:element name="{local-name()}" namespace="http://www.abc.com/s/v2.0">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>

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

<xsl:template match="//*[local-name()='QueryRequest']/@version">
<xsl:attribute name="version">
<xsl:value-of select="$newversion"/>
</xsl:attribute>

</xsl:template>     

使用上面的XSL文件输出: -

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
</soapenv:Header>
<soapenv:Body><ns7:QueryRequest version="1" xmlns=""
xmlns:ns6="http://www.abc.com/s/v1.0" 
xmlns:ns7="http://www.abc.com/s/v2.0"/>

</soapenv:Body>
</soapenv:Envelope>

预期产出:

<soapenv:Envelope 
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:v2="http://www.abc.com/s/v2.0">
<soapenv:Header/>
<soapenv:Body>
<v2:QueryRequest version="2.0">
<subject>
<dataList>
<!--1 or more repetitions:-->
<dataset>
<type>company</type>
<value>abc</value>
</dataset>
<dataset>
<type>user</type>
<value>xyz</value>
</dataset>
</dataList>
</subject>
<!--Optional:-->
<testList>
<!--1 or more repetitions:-->
<criteria>
<type>test</type>
<value>972</value>
</criteria>
<criteria>
<type>test2</type>
<value>false</value>
</criteria>
</testList>
</v2:QueryRequest>
</soapenv:Body>
</soapenv:Envelope>

Spring config代码触发此转换 -

<int-xml:xslt-transformer  id="v2transformer"                                     xsl-resource="classpath:transformtoversion2.xslt" 
input-channel="AChannel" output-channel="BChannel" 
result-transformer="resultTransformer"> 
</int-xml:xslt-transformer> 

1 个答案:

答案 0 :(得分:3)

对我来说,一旦我通过将根元素重命名为xsl:stylesheet而不是xsl:transform来更正XSLT,我几乎得到了正确的输出

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://www.abc.com/s/v1.0">
<soapenv:Header/>
<soapenv:Body>
<QueryRequest xmlns="http://www.abc.com/s/v2.0" version="2">
<subject xmlns="">
<dataList>
<!--1 or more repetitions:-->
<dataset>
<type>company</type>
<value>abc</value>
</dataset>
<dataset>
<type>user</type>
<value>xyz</value>
</dataset>
</dataList>
</subject>
<!--Optional:-->
<testList xmlns="">
<!--1 or more repetitions:-->
<criteria>
<type>test</type>
<value>972</value>
</criteria>
<criteria>
<type>test2</type>
<value>false</value>
</criteria>
</testList>
</QueryRequest>
</soapenv:Body>
</soapenv:Envelope>

version="2"而不是version="2.0"所需的唯一语义上的显着差异,可通过向

添加一些引号来修复
<xsl:param name="newversion" select="'2.0'" />

将param值设置为 string 2.0而不是 number 2。


对于外观差异,如果要从根元素中删除未使用的xmlns:v1并使用QueryRequest元素的前缀而不是默认命名空间(然后由{{1对于孩子们来说,你需要更像这样的东西

xmlns=""

我在<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:old="http://www.abc.com/s/v1.0" exclude-result-prefixes="old" xmlns:v2="http://www.abc.com/s/v2.0"> <xsl:output method="xml" encoding="utf-8" indent="yes" version="1.0" /> <xsl:param name="newversion" select="'2.0'"/> <!-- fix namespace declarations on root element --> <xsl:template match="/*"> <xsl:element name="{name()}" namespace="{namespace-uri()}"> <!-- copy the v2: binding from the stylesheet document --> <xsl:copy-of select="document('')/xsl:stylesheet/namespace::v2" /> <xsl:apply-templates select="@* | node()" /> </xsl:element> </xsl:template> <!-- replace namespace of elements in old namespace --> <xsl:template match="old:*"> <xsl:element name="v2:{local-name()}"> <xsl:apply-templates select="@* | node()"/> </xsl:element> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="old:QueryRequest/@version"> <xsl:attribute name="version"> <xsl:value-of select="$newversion"/> </xsl:attribute> </xsl:template> </xsl:stylesheet> 模板中使用<xsl:element>而不是<xsl:copy>,因为/*会复制原始代码中的命名空间绑定。


从评论中,您现在希望将所有copy值置为大写。您只需添加一个额外的模板即可实现此目的

<type>

在XPath 1.0中没有简单的<xsl:template match="type/text()"> <xsl:value-of select="translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" /> </xsl:template> 函数,但是你可以使用to-upper-case,它通过字符串X替换Y中的每个字符与中的相同位置的字符ž。

这将转换所有 translate(X, Y, Z)元素,如果您只想转换数据集类型而不是条件类型,那么只需使用更具体的type