简体   繁体   English

创建XSLT转换以展平multiRef编码的SOAP消息

[英]Creating XSLT transform to flatten multiRef encoded SOAP message

Input is a mutliRef encoded SOAP message/document. 输入是经过mutliRef编码的SOAP消息/文档。 How do you use XSLT to flatten multiRefs. 如何使用XSLT展平multiRef。 Multiref nodes can be referenced used multiple times, and themselves recursively reference other multiRef nodes. 可以多次引用multiref节点,并且它们递归地引用其他multiRef节点。

The only pieces of the structure that are safe to refer to, are multiRef elements and @id and @href attributes. 唯一可以安全引用的结构是multiRef元素以及@id和@href属性。 Other elements or namespaces could change. 其他元素或名称空间可能会更改。

Sample input message is: 样本输入消息为:

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:getAccountDTOResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:ns1="http://www.example.com/pw/services/PWServices">
      <getAccountDTOReturn href="#id0" />
    </ns1:getAccountDTOResponse>
    <multiRef id="id0" soapenc:root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xsi:type="ns2:Account"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:ns2="urn:PWServices">
      <ID href="#id1" />
      <accountNumber xsi:type="soapenc:string"></accountNumber>
      <accountType xsi:type="soapenc:string"></accountType>
      <clientData xsi:type="soapenc:Array" xsi:nil="true" />
      <name xsi:type="soapenc:string"></name>
      <parentRef xsi:type="soapenc:string"></parentRef>
    </multiRef>
    <multiRef id="id1" soapenc:root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xsi:type="xsd:long"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
    0</multiRef>
  </soapenv:Body>
</soapenv:Envelope>

Expected output is: 预期输出为:

<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <ns1:getAccountDTOResponse xmlns:ns1="http://www.example.com/pw/services/PWServices"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

      <getAccountDTOReturn xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:ns2="urn:PWServices"
      soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
      xsi:type="ns2:Account">
        <ns1:ID soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        xsi:type="xsd:long">0</ns1:ID>
        <ns1:accountNumber xsi:type="soapenc:string" />
        <ns1:accountType xsi:type="soapenc:string" />
        <ns1:clientData xsi:type="soapenc:Array" xsi:nil="true" />
        <ns1:name xsi:type="soapenc:string" />
        <ns1:parentRef xsi:type="soapenc:string" />
      </getAccountDTOReturn>
    </ns1:getAccountDTOResponse>
  </soapenv:Body>
</soapenv:Envelope>

Update: In the example above, logically, what should happen is: 更新:在上面的示例中,逻辑上应该发生的是:

On the first pass, getAccountDTOResponse contains @href="#id0", so that element is replaced with all the children multiRef element with @id="id0", with exception of. 在第一遍中,getAccountDTOResponse包含@href =“#id0”,因此该元素将被所有带有@ id =“ id0”的子multiRef元素替换,但例外。

On the second pass, @href="#id1" should be discovered, and ID element should be replaced with contents of element with @id="id1". 在第二遍中,应发现@href =“#id1”,并应将ID元素替换为具有@ id =“ id1”的元素的内容。

No multiRef elements should exists in the output. 输出中不应存在multiRef元素。 No attributes @id or @href should exists in output, if there were involved in this whole multiRef mess. 如果整个multiRef混乱都涉及到,则输出中不应该存在@id或@href属性。

Alex, I'm not matching your output completely but here is how you can resolve your document by hrefs. 亚历克斯,我不完全匹配您的输出,但是这是通过hrefs解析文档的方法。

This stylesheet: 此样式表:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" >

    <xsl:key name="multiref-by-id" match="multiRef" use="@id"/>

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

    <xsl:template match="*[starts-with(@href, '#')]">
        <xsl:copy>
            <xsl:apply-templates select="@* |
             key('multiref-by-id', substring-after(@href, '#'))/@* |
            key('multiref-by-id', substring-after(@href, '#'))/node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@href[starts-with(., '#')] | multiRef[@id] | @soapenc:root"/>

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

Given this input: 鉴于此输入:

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <ns1:getAccountDTOResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                                   xmlns:ns1="http://www.example.com/pw/services/PWServices">
            <getAccountDTOReturn href="#id0"/>
        </ns1:getAccountDTOResponse>
        <multiRef id="id0" soapenc:root="0"
                  soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                  xsi:type="ns2:Account"
                  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
                  xmlns:ns2="urn:PWServices">
            <ID href="#id1"/>
            <accountNumber xsi:type="soapenc:string"></accountNumber>
            <accountType xsi:type="soapenc:string"></accountType>
            <clientData xsi:type="soapenc:Array" xsi:nil="true"/>
            <name xsi:type="soapenc:string"></name>
            <parentRef xsi:type="soapenc:string"></parentRef>
        </multiRef>
        <multiRef id="id1" soapenc:root="0"
                  soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                  xsi:type="xsd:long"
                  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
            0
        </multiRef>
    </soapenv:Body>
</soapenv:Envelope>

Produces the following result: 产生以下结果:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <ns1:getAccountDTOResponse xmlns:ns1="http://www.example.com/pw/services/PWServices"
                                   soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <getAccountDTOReturn id="id0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                                 xsi:type="ns2:Account">
                <ID xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="urn:PWServices" id="id1"
                    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:long">
                    0
                </ID>
                <accountNumber xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="urn:PWServices"
                               xsi:type="soapenc:string"/>
                <accountType xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="urn:PWServices"
                             xsi:type="soapenc:string"/>
                <clientData xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="urn:PWServices"
                            xsi:type="soapenc:Array" xsi:nil="true"/>
                <name xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="urn:PWServices"
                      xsi:type="soapenc:string"/>
                <parentRef xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="urn:PWServices"
                           xsi:type="soapenc:string"/>
            </getAccountDTOReturn>
        </ns1:getAccountDTOResponse>


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

I think that this apporach could be easily customized to fit your needs. 我认为可以轻松定制此方法以满足您的需求。 I would like to outline that the provided stylesheet operates on @hrefs and does not take in account any element names. 我想概述一下,提供的样式表可在@hrefs运行,并且不考虑任何元素名称。 Therefore it can be used flexibly without paying attention to the referring element names. 因此,它可以灵活使用,而无需注意引用元素的名称。 However all the reference should be named multiRef s but this can be easily customized too. 但是,所有引用都应命名为multiRef但是也可以轻松对其进行自定义。

This stylesheet: 此样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
    <xsl:key name="kMultiRefById" match="multiRef" use="@id"/>
    <xsl:output method="xml"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="getAccountDTOReturn">
        <xsl:variable name="vRefer"
                      select="key('kMultiRefById',substring(@href,2))"/>
        <xsl:copy>
            <xsl:copy-of select="$vRefer/namespace::*"/>
            <xsl:apply-templates select="$vRefer/@*|$vRefer/node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="multiRef|multiRef/@id|multiRef/@soapenc:root"/>
</xsl:stylesheet>

Output: 输出:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <ns1:getAccountDTOResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                                   xmlns:ns1="http://www.example.com/pw/services/PWServices">
            <getAccountDTOReturn soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                                 xsi:type="ns2:Account"
                                 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
                                 xmlns:ns2="urn:PWServices">
                <ID href="#id1"></ID>
                <accountNumber xsi:type="soapenc:string"></accountNumber>
                <accountType xsi:type="soapenc:string"></accountType>
                <clientData xsi:type="soapenc:Array" xsi:nil="true"></clientData>
                <name xsi:type="soapenc:string"></name>
                <parentRef xsi:type="soapenc:string"></parentRef>
            </getAccountDTOReturn>
        </ns1:getAccountDTOResponse>
    </soapenv:Body>
</soapenv:Envelope>

Note : Keys for cross references. 注意 :交叉引用的键。 Identity rule. 身份规则。 Empty rules for stripping. 剥离的空规则。 Copying namespaces nodes might not be posible for every XSLT processor , although I only know about Mozilla's TransforMiiX wich doesn't have implemented namespaces:: axis. 尽管我只知道Mozilla的TransforMiiX并没有实现namespaces:: axis,但并不是每个XSLT处理器都可以复制名字空间节点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM