XSLT 从 XML 到 XML 文档的转换 [英] XSLT transformation from XML to XML document

查看:22
本文介绍了XSLT 从 XML 到 XML 文档的转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need help to get correct XSL transformation, I am expecting the source XML to be copied as is and do the required updates to the target XML file. Right now i am trying 2 things, first is to copy source to target XML and second is to update the namespace URL and version attribute of root element. Please find the code below and let me know what is going wrong because i am getting only root element in the target xml, the content is missing, the end tag for root element is missing and also the attribute version was not updated.

源 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 文件输出:-

Output using above XSL file:-

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

Spring config Code which triggers this transformation -

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

推荐答案

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

For me, once I correct the XSLT by renaming the root element to xsl:stylesheet instead of xsl:transform, I get almost the correct output

<?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",这可以通过添加一些引号来解决

the only semantically significant difference from what you require being version="2" rather than version="2.0", which can be fixed by adding some quotes to

<xsl:param name="newversion" select="'2.0'" />

将参数值设置为 string 2.0 而不是 number 2.

to set the param value to the string 2.0 instead of the number 2.

对于外观差异,如果您想从根元素中删除未使用的 xmlns:v1 并使用 QueryRequest 元素的前缀而不是默认命名空间(然后由 xmlns="" 为孩子取消)然后你需要更像这样的东西

For the cosmetic differences, if you want to remove the unused xmlns:v1 from the root element and use a prefix for the QueryRequest element instead of a default namespace (which is then countermanded by xmlns="" for the children) then you need something more like this

<?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>

我在 /* 模板中使用 而不是 因为 copy 从原始标签复制命名空间绑定.

I use <xsl:element> instead of <xsl:copy> in the /* template because copy copies the namespace bindings from the original tag.

根据注释,您现在要大写所有 值.您只需添加一个额外的模板即可实现这一点

From the comments, you now want to upper-case all the <type> values. You can achieve this simply by adding one extra template

<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 中的每个字符.

There isn't a simple to-upper-case function as such in XPath 1.0, but you can use translate(X, Y, Z), which goes through the string X replacing each character in Y with the character at the same position in Z.

这将转换所有 type 元素,如果您只想转换数据集类型而不是条件类型,那么只需使用更具体的 match="数据集/类型/文本()".

This will convert all type elements, if you only want to convert the dataset types and not the criteria types then just use a more specific match="dataset/type/text()".

这篇关于XSLT 从 XML 到 XML 文档的转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆