【问题标题】:XSLT transformation from XML to XML document从 XML 到 XML 文档的 XSLT 转换
【发布时间】:2013-09-17 17:20:58
【问题描述】:

我需要帮助来获得正确的 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> 

【问题讨论】:

    标签: xml spring xslt


    【解决方案1】:

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

    将参数值设置为 string 2.0 而不是 number 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>
    

    我在/* 模板中使用&lt;xsl:element&gt; 而不是&lt;xsl:copy&gt;,因为copy 从原始标记复制命名空间绑定。


    在 cmets 中,您现在想要将所有 &lt;type&gt; 值大写。您只需添加一个额外的模板即可实现此目的

    <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 将 Y 中的每个字符替换为 Z 中相同位置的字符。

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

    【讨论】:

    • 感谢完美的灵魂,对我来说这还没有完成,因为当我使用你的 XSL 时,我得到了我期望的 元素,原因是当我转换源 XML以 XML 为目标,然后使用版本 2 模式进行解组,然后进行编组,现在在模式的版本 2 中,所有类型都使用大写字母 :-),这就是输出中缺少所有 元素的原因。 ...您能否建议如何以简单的方式将 元素值更新为 CAPS?
    • 例如我需要将元素键入为 COMPANYSERVICE 等等......
    • 优秀...我会试试这个..非常感谢,不胜感激。
    猜你喜欢
    • 1970-01-01
    • 2017-06-02
    • 2020-07-28
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多