从XML到XML文档的XSLT转换

3
我需要帮助正确进行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>

"

Expected Output:

<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配置代码 -

<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个回答

4

对我来说,一旦我通过将根元素从xsl:transform重命名为xsl:stylesheet来更正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'" />

将参数值设置为字符串2.0而不是数字2。
对于格式上的差异,如果你想要从根元素中删除未使用的xmlns:v1,并且使用一个前缀代替QueryRequest元素的默认命名空间(然后通过子元素的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>值转换为大写。您可以通过添加一个额外的模板来轻松实现此目的。
<xsl:template match="type/text()">
  <xsl:value-of select="translate(., 'abcdefghijklmnopqrstuvwxyz',
                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
</xsl:template>

在XPath 1.0中,没有简单的to-upper-case函数,但是你可以使用translate(X, Y, Z)来实现,该函数遍历字符串X,并用Z中相同位置的字符替换Y中的每个字符。
如果你只想转换数据集类型而不是条件类型,那么只需使用更具体的match="dataset/type/text()"即可将所有类型元素转换。

感谢您提供的完美解决方案,但在我的环境中,这还不完整,因为当我使用您的XSL时,我得到了我期望的结果,除了<type>元素。原因是当我将源XML转换为目标XML时,然后使用版本2模式进行取消编组和编组时,在版本2的模式中,所有类型都是大写的 :-) 所以所有<type>元素都缺失了输出...您能否建议一种简单的方法来更新<type>元素值为大写? - user2748318
例如,我需要输入元素,使其如下所示:<type>公司</type>或<type>服务</type>等。 - user2748318
非常好,我会尝试的。非常感谢,非常感激。 - user2748318

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接