代码之家  ›  专栏  ›  技术社区  ›  hotmeatballsoup

从输入的属性动态生成输出XML的XSL转换

  •  0
  • hotmeatballsoup  · 技术社区  · 6 年前

    对于这段时间的事,我提前道歉,只有一些重要的细节来充分阐述我的问题,但这(应该是!)它的核心是一个简单的XSLT问题。


    我有以下3个XML文档(作为其结构的示例):

    <?xml version="1.0" encoding="UTF-8" ?>
    <rabbitEnvelope>
        <action>YES</action>
        <logId>123</logId>
        <payload class="rabbit">
                <id>1</id>
                <name>Some Bunny</name>
                <easter>false</easter>
        </payload>
    </rabbitEnvelope>
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <bearEnvelope>
        <action>NO</action>
        <logId>456</logId>
        <payload class="bear">
                <type>Polar</type>
                <weight>655</weight>
        </payload>
    </bearEnvelope>
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <dogEnvelope>
        <action>MAYBE</action>
        <logId>789</logId>
        <payload class="dog">
                <goodboy>YES!</goodboy>
                <eats>Everything</eats>
            <canFetch>true</canFetch>
            <moniker>Fido</moniker>
        </payload>
    </dogEnvelope>
    

    我们称之为 经典版 “这3个不同的XML文档。

    我的应用程序现在将接收“ 新版本 “其中,我需要编写一个XSL转换来将新版本转换为经典版本。这些XML文档的新版本(同样是示例)如下所示:

    <?xml version="1.0" encoding="UTF-8" ?>
    <envelope>
        <action>YES</action>
        <auditId>123</auditId>
        <payload class="rabbit">
            <id>1</id>
            <name>Some Bunny</name>
            <easter>false</easter>
        </payload>
    </envelope>
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <envelope>
        <action>NO</action>
        <auditId>456</auditId>
        <payload class="bear">
            <type>Polar</type>
            <weight>655</weight>
        </payload>
    </envelope>
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <envelope>
        <action>MAYBE</action>
        <auditId>789</auditId>
        <payload class="dog">
            <goodboy>YES!</goodboy>
            <eats>Everything</eats>
            <canFetch>true</canFetch>
            <moniker>Fido</moniker>
        </payload>
    </envelope>
    

    因此,在这些“新版本”中,最外层的XML元素将 总是 是一个 <envelope> 元素。这个 <action> 新版本的元素与经典版本中的元素相同。新的 /envelope/auditId 与经典版相同 <logId> ( /rabbitEnvelope/logId 等)。和 /envelope/payload 经典版也一样( /bearEnvelope/payload 等)。

    因此,我需要编写一个XSL转换,它将转换XML的新版本( <包络线; 有效载荷)。通常情况下:

    • 这个 /envelope/payload/@class 值确定经典版本最外层元素的名称。因此是 /envelope/payload/@class='rock' ,则其“经典”版本的最外层/根元素将是 <rockEnvelope> .
    • 我想复印 /envelope/action /<rootElementEnvelope>/action . 因此如果 /envelope/action='YES' 然后 /<rootElementEnvelope>/action='YES' .
    • 我想复制 价值 属于 /信封/AuditID <rootElementEnvelope>/logId . 因此如果 /envelope/auditId='123' 然后 /<rootElementEnvelope>/logId='123' .
    • 我想复制 整个的 /信封/有效载荷 /<rootElementEnvelope>/payload ,没有任何变化。

    我对通用XSLT的第一次尝试是:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
        <xsl:template match="//envelope">
        <!-- The rabbitEnvelope element needs to be dynamically generated! -->
        <rabbitEnvelope>
            <action><xsl:value-of select="../action"/></action>
            <logId><xsl:value-of select="../auditId"/></logId>
            <payload class="???">
                <!-- All the XML from inside the source payload tag-->
            </payload>
        </rabbitEnvelope>
    </xsl:template>      
    

    但是,由于我的需求具有相同/共同的动态特性,这里有一些问题。

    1. 自从 <payload class=???> 值确定转换的/结果的根标记是否是 <rabbitEnvelope> , <bearEnvelope> , <dogEnvelope> , <Rockenvelope> (或任何其他类型, 还有很多! )我不能只是硬编码 <rabbitenvelope> 进入我的XSLT。
    2. 相信 我的使用 <action><xsl:value-of select="../action"/></action> <logId><xsl:value-of select="../auditId"/></logId> 是正确的,但是如果你发现它有什么问题,请告诉我!
    3. 我不知道如何生成输出/结果 <payload/> 标签,因为它只是输入XML中任何内容的直接副本,不能硬编码。

    考虑到需求的动态特性,我有什么想法可以实现期望的转换吗? 事先谢谢!

    1 回复  |  直到 6 年前
        1
  •  1
  •   michael.hor257k    6 年前

    怎么样:

    XSLT2.0(也与XSLT1.0兼容)

    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="/envelope">
        <xsl:element name="{payload/@class}Envelope">
            <xsl:copy-of select="action"/>
            <logId>
                <xsl:value-of select="auditId"/>
            </logId>
            <xsl:copy-of select="payload"/>
        </xsl:element>
    </xsl:template>
    
    </xsl:stylesheet>