如何将xml格式化为soap响应格式?

时间:2015-08-31 18:36:11

标签: c# xml soap

我需要将xml格式化为soap1.1响应信封。

首先,我的业务对象。我知道疯狂的筑巢。我不允许改变结构:

    [DataContract]  
    public class DIVSReturnObject  
    {  
        public CoverageResponseDocument coverageResponseDoc { get; set; }  
        public DIVSReturnObject()  
        {  
            coverageResponseDoc = new CoverageResponseDocument();
        }  
    }  

    [DataContract]  
    public class CoverageResponseDocument  
    {
         public Detail detail { get; set; }

         public CoverageResponseDocument()
         {
             detail = new Detail();
         }
    }  
    [DataContract]
    public class Detail
    {
        public PolicyInformation policyInformation { get; set; }
        public VehileInformation vehicleInformation { get; set; }

        public Detail()
        {
            policyInformation = new PolicyInformation();
        }
     }  

    [DataContract]
    public class PolicyInformation
    {
        public OrganizationDetails organizationDetails { get; set; }
        public PolicyDetails policyDetails { get; set; }
        public CoverageStatus coverageStatus { get; set; }

        public PolicyInformation()
        {
            coverageStatus = new CoverageStatus();
        }
    }  

    [DataContract]
    public class CoverageStatus
    {
        public ResponseDetails responseDetails { get; set; }

        public CoverageStatus()
        {
            responseDetails = new ResponseDetails();
        }
    }  

    [DataContract]
    public class ResponseDetails
    {
        [DataMember]
        [XmlAttribute(AttributeName = "ResponseCode")]
        public string ResponseCode { get; set; }
        [DataMember]
        [XmlAttribute(AttributeName = "UnconfirmedReasonCode")]
        public string UnconfirmedReasonCode { get; set; }
    }  

接下来,我将所需对象序列化为XML的代码:

    XmlDocument xmlDoc = new XmlDocument();  
    XmlSerializer xmlSerializer = new XmlSerializer(divsResponse.GetType());
    using (MemoryStream xmlStream = new MemoryStream())
    {
        xmlSerializer.Serialize(xmlStream, divsResponse);
        xmlStream.Position = 0;

        xmlDoc.Load(xmlStream);
        return xmlDoc.InnerXml;
    }  

接下来,生成的XML字符串。请注意,ResponseCode和UnconfirmedReasonCode是它们应该是它们自己的元素的属性:

    <?xml version="1.0"?>
    <DIVSReturnObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <coverageResponseDoc>
            <detail>
                <policyInformation>
                    <coverageStatus>
                        <responseDetails ResponseCode="Unconfirmed" UnconfirmedReasonCode="VIN1" />
                    </coverageStatus>
                </policyInformation>
            </detail>
        </coverageResponseDoc>
    </DIVSReturnObject>  

最后,带有正确名称空间的所需信封(如何添加?):

    <?xml version="1.0" encoding="UTF-8"?>  
    <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">  
        <SOAP-ENV:Body>  
            <CoverageResponseDocument PublicationVersion="00200809" PublicationDate="2008-11-05" xmlns="http://www.iicmva.com/CoverageVerification/">  
                <Detail>  
                    <PolicyInformation>  
                        <CoverageStatus>  
                            <ResponseDetails>  
                                <ResponseCode>Unconfirmed</ResponseCode>  
                                <UnconfirmedReasonCode>VIN1</UnconfirmedReasonCode>  
                            </ResponseDetails>  
                        </CoverageStatus>  
                        <OrganizationDetails>   
                            <NAIC>12345</NAIC>  
                            <!-- this can be echoed from the request or provide the actual NAIC that has evidence of coverage -->  
                        </OrganizationDetails>  
                        <PolicyDetails>  
                            <!-- this section can be echoed from the request -->  
                            <VerificationDate>2015-01-01T00:00:00.000</VerificationDate>  
                            <PolicyKey>UNKNOWN</PolicyKey>  
                            <PolicyState>CT</PolicyState>  
                        </PolicyDetails>  
                    </PolicyInformation>  
                </Detail>  
            </CoverageResponseDocument>  
        </SOAP-ENV:Body>  
    </SOAP-ENV:Envelope>

1 个答案:

答案 0 :(得分:0)

在我希望在您的情况下适用的以下条件下,确实有一种非常快速的方法来解决您的问题。时间就是金钱,对吗?

  • 肥皂反应是相当静态的(没有收集等等。只需要一整个字段来填写)。
  • 您无法完全控制代码库(DOM),因此希望将解决方案与DOM代码分离。对于DOM,我指的是您在问题中显示的数据模型类。

我在下面展示的解决方案的缺点是:

  • 不是&#34;泛型&#34;应该适用于所有情况的解决方案。 (适合你当前的问题,但也许不适合你的下一个)。
  • 与文本模板一样酷,有一个可能的错误来源,一旦事情变得更复杂(动态) - 很难证明你将始终产生正确的输出。也许那时,其他解决方案,如可审查的xslt转换,甚至更好的合同首先 - &gt;代码生成DOM&#34; appraoch更可靠。

我建议你先将自己温暖一下,然后再将其添加到主项目中。一个小的C#控制台应用程序项目就可以了。

  1. 创建您的玩具控制台应用程序(文件 - &gt;新项目 - &gt; C# - &gt; ConsoleApp)。
  2. 在解决方案探索和添加新项目中右键单击您的项目 - &gt;运行时文本模板。使用&#34;运行时文本模板&#34;非常重要。而不是&#34;文字模板&#34;在你的情况下。给它一个正确的名称(我在我的演示代码中使用了#34; MySoapResponse.tt&#34;。
  3. 在生成的.tt文件中,该文件现在是项目项目的一部分,将所需的肥皂输出复制并粘贴到文件中已包含的内容之下。
  4. 创建一个虚拟DOM,只是为了拥有与应用程序中相同的场景。
  5. 将新的C#代码文件添加到项目中,并在代码隐藏.tt代码使用的同一名称空间中添加一个partical类,其中包含生成的模板类的名称(部分)。添加一个构造函数,您可以将您要用于生成消息的DOM实例作为参数传递。
  6. 创建一些Query函数或只创建一个Document {get;}属性。
  7. 在您的控制台应用程序主界面中,创建一个包含一些数据的DOM实例。
  8. 还要创建生成的生成器对象的实例。
  9. 调用TransformText()方法并将字符串保存到磁盘上的文件中以供检查。
    1. Rince并重复:通过在需要DOM数据的位置添加越来越多的降价语句来修改.tt模板。
  10. 正如你所看到的 - 完成了10个步骤。

    这就是转换代码的样子(甚至比XmlSerializer调用更简单):

    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                MyDOM.Root document = MyDOM.Root.CreateExampleDocument();
                MySoapResponse responseGenerator = new MySoapResponse(document);
    
                System.IO.File.WriteAllText(@"E:\temp\blabla.txt", responseGenerator.TransformText());
    
                System.Console.WriteLine("Done transforming!");
    
            }
        }
    }
    

    而这 - 为了完整起见,我为这个答案发明了我的miniDOM:

    namespace MyDOM
    {
        internal class Root
        {
            internal ChildA childA { get; set; }
            internal ChildB childB { get; set; }
    
            internal static Root CreateExampleDocument()
            {
                Root r = new Root();
                r.childA = new ChildA();
                r.childB = new ChildB();
                r.childA.ResponseCode = "I have my reasons!";
                r.childA.ReasonCode = "I have response code using T4!";
                return r;
            }
        }
    
        internal class ChildA
        {
            internal string ResponseCode { get; set; }
            internal string ReasonCode { get; set; }
        }
    
        internal class ChildB
        {
    
        }
    }
    

    我只添加了2个项目 - 这足以展示它是如何运作的。

    当然,在.tt文件中,我还添加了足够的内容来覆盖这两个项目。

    <#@ template language="C#" #>
    <#@ assembly name="System.Core" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="System.Collections.Generic" #>
    <?xml version="1.0" encoding="UTF-8"?>  
        <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">  
            <SOAP-ENV:Body>  
                <CoverageResponseDocument PublicationVersion="00200809" PublicationDate="2008-11-05" xmlns="http://www.iicmva.com/CoverageVerification/">  
                    <Detail>  
                        <PolicyInformation>  
                            <CoverageStatus>  
                                <ResponseDetails>  
                                    <ResponseCode><#=ResponseCode()#></ResponseCode>  
                                    <UnconfirmedReasonCode><#=ReasonCode()#></UnconfirmedReasonCode>  
                                </ResponseDetails>  
                            </CoverageStatus>  
                            <OrganizationDetails>   
                                <NAIC>12345</NAIC>  
                                <!-- this can be echoed from the request or provide the actual NAIC that has evidence of coverage -->  
                            </OrganizationDetails>  
                            <PolicyDetails>  
                                <!-- this section can be echoed from the request -->  
                                <VerificationDate>2015-01-01T00:00:00.000</VerificationDate>  
                                <PolicyKey>UNKNOWN</PolicyKey>  
                                <PolicyState>CT</PolicyState>  
                            </PolicyDetails>  
                        </PolicyInformation>  
                    </Detail>  
                </CoverageResponseDocument>  
            </SOAP-ENV:Body>  
        </SOAP-ENV:Envelope>
    

    我在.tt模板中调用的调用(例如<#=ResponseCode())是我添加到生成器对象的部分类部分的方法。

    namespace ConsoleApplication2
    {
        public partial class MySoapResponse
        {
            MyDOM.Root Document { get; }
            internal MySoapResponse(MyDOM.Root document)
            {
                Document = document;
            }
            internal string ResponseCode()
            {
                return Document.childA.ResponseCode;
            }
            internal string ReasonCode()
            {
                return Document.childA.ReasonCode;
            }
        }
    }
    

    就是这样。实际编写了一些点击和几行代码(让它成为50行)。肯定比手工使用StringBuilder更好。