Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 创建XML子节点,忽略父节点_C#_Xml_Soap - Fatal编程技术网

C# 创建XML子节点,忽略父节点

C# 创建XML子节点,忽略父节点,c#,xml,soap,C#,Xml,Soap,根据MSDN文件: 还可以将数组序列化为XML元素的平面序列,方法是对返回数组的字段应用XmlElementAttribute,如下所示 所需的XML架构: <xs:element minOccurs="0" maxOccurs="unbounded" name="ResponseLineTest" type="OrderLn" /> 但是:使用.NET 4.51,我得到以下模式: <xs:element minOccurs="0" name="ResponseLine"

根据MSDN文件:

还可以将数组序列化为XML元素的平面序列,方法是对返回数组的字段应用XmlElementAttribute,如下所示

所需的XML架构:

<xs:element minOccurs="0" maxOccurs="unbounded" name="ResponseLineTest" type="OrderLn" />
但是:使用.NET 4.51,我得到以下模式:

 <xs:element minOccurs="0" name="ResponseLine" nillable="true" type="tns:ArrayOfOrderLn"/>


如何标记我的C#类和属性,使WSDL输出看起来与上面(和文档)一样?

对Web服务定义进行必要的更改

首先,必要的复杂类型
PlaceOrder
的定义没有提到类型
tns:OrderLine
的元素。我想你必须改变元素的定义。因为您的Web服务的定义非常松散,所以它的工作方式与您在问题中所展示的一样

以下是
PlaceOrder
请求的当前定义。这意味着,
PlaceOrder
元素是请求参数所必需的

<wsdl:message name="IService_PlaceOrder_InputMessage">
    <wsdl:part name="parameters" element="tns:PlaceOrder"/>
</wsdl:message>
这意味着,您还可以发送所有内容。您的Web服务不知道
PlaceOrder
上下文中的
OrderLine
元素,因为此处未定义该元素。您必须将
PlaceOrder
元素的定义更改为以下符号

<xs:element name="PlaceOrder">
    <xs:complexType>
        <xs:sequence>
            <xs:element minOccurs="0" name="userToken" nillable="true" type="xs:string"/>
            <xs:element minOccurs="0" name="ediOrder" nillable="true" type="q1:order"/>
            <xs:element minOccurs="0" name="OrderLine" nillable="true" type="q1:ArrayOfOrderLine"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>
此定义表示,您需要具有父节点的
OrderLine
复杂类型。因此,父节点完全按照wsdl文件中的定义发生。要省略父节点,必须按如下方式重新定义
PlaceOrder
复杂类型:

<xs:complexType name="ArrayOfOrderLine">
    <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" name="OrderLine" nillable="true" type="tns:OrderLine"/>
    </xs:sequence>
</xs:complexType>
<xs:element name="PlaceOrder">
    <xs:complexType>
        <xs:sequence>
            <xs:element minOccurs="0" name="userToken" nillable="true" type="xs:string"/>
            <xs:element minOccurs="0" name="ediOrder" nillable="true" type="q1:order"/>
            <xs:element minOccurs="0" maxOccurs="unbounded" name="OrderLine" nillable="true" type="tns:OrderLine"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>
上面显示的PHP代码显示了
PlaceOrder
value对象。正如您所看到的,在webservice定义中定义的所有元素都作为此类的属性出现。这个类是
PlaceOrder
复杂类型的精确php实现。可以说,所有复杂类型都是PHP类。此外,可接受的方法参数主要是
SoapVar
实例。这对于soap客户机很重要,因为这保证了最终的xml结构是正确的

OrderLine值对象

<?php
namespace Webservice\Entity;

class OrderLine 
{
    protected $AdditionalCustomerReferenceNumber;
    protected $LineID;
    protected $OrderedArticle;
    protected $PortalReference;

    // getters and setters here
}
"; }catch(SoapFault$fault){ 回声“; var_dump($故障); 回声“; } 结论


您的web服务定义非常不精确。因此,您只需重新考虑参数的定义,并在WSDL文件中更精确地定义它们。然后它也与PHP一起工作。PHP在其soap扩展中严格使用web标准。

TL;DR您的问题是.NET有两个单独的XML序列化程序,并且,您正在创建一个WCF服务,您需要通过应用到您的应用程序切换到使用
XmlSerializer

详情如下。假设您拥有以下WCF服务合同(您的问题中未显示):

您希望此服务生成的XML具有包含重复序列的
元素的架构,例如,如下所示:


因此,您可以将该属性应用于
ResponseLine
,以强制以这种方式将其序列化为XML。但是,当您为服务生成WSDL时,您会得到一个如下所示的模式:


架构包括一个额外的中间类型
ArrayOfOrderLn
,并且未使用重写的元素名
“ResponseLineTest”
。显然,
[xmlementattribute(“ResponseLineTest”)]
属性被完全忽略。为什么会这样

事实证明,此行为记录在中,这说明您的服务根本没有使用
XmlSerializer
,而是使用一个忽略
[XmlElement]
属性的不同序列化程序:

默认情况下,WCF使用DataContractSerializer类序列化数据类型

有时,您可能必须手动切换到XmlSerializer。例如,在以下情况下会发生这种情况:

  • 当对消息中显示的XML进行精确控制非常重要时
在这种情况下,需要对XML进行精确控制,特别是强制在不使用外部容器元素的情况下序列化
ResponseLine
属性。但是,在不使用外部容器元素的情况下序列化集合是非常困难的,因此必须通过应用
[XmlSerializerFormat]
到您的服务合同:


现在,为您的服务生成的WSDL将符合要求。

有任何具有xsd定义的WSDL可用吗?PHP使用自己的SoapClient类有点棘手。通常您必须使用PHP SoapVar对象才能获得正确的xml结构。有来自worldstandard创建者(ediWheel btw)的xsd,但正如我在使用XSD2代码时所学到的,这些xsd可以用很多方式进行解释。我只是想澄清一下。我不是做PHP部分的人。我们的客户端是。我返回强类型数据类。我使用WSDLBrowser.com进行测试,或者你问过我WSDL是否在某个地方可用吗?如果是的话。你甚至可以从我发布的网站上自己获取它服务:)上面显示的PHP输出是您的客户正在创建的请求,还是您的服务发送回您的客户的响应?我关注的是响应。然而,我尝试调用我的SOAP服务,无论是否使用父订单行。无论哪种方式都可以。哦,天哪,恐怕我整天都在胡闹WSDL,有蜜蜂n许多版本,从一分钟到一分钟,一些定义了orderline,一些没有,以调试不同的场景。orderline现在就在那里。为了调试,我添加了一个非常简单的方法,称为PlaceOrderTestNoInput。你能检查一下这个方法是否有相同的不精确定义吗?你认为它状态不好,我为此道歉。
<xs:element name="PlaceOrder">
    <xs:complexType>
        <xs:sequence>
            <xs:element minOccurs="0" name="userToken" nillable="true" type="xs:string"/>
            <xs:element minOccurs="0" name="ediOrder" nillable="true" type="q1:order"/>
            <xs:element minOccurs="0" maxOccurs="unbounded" name="OrderLine" nillable="true" type="tns:OrderLine"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>
<?php
namespace Webservice\Entity;
use ArrayObject;
use SoapVar;

class PlaceOrder
{
    protected $userToken;
    protected $ediOrder;
    protected $OrderLine;

    public function __construct()
    {
        $this->OrderLine = new ArrayObject();
    }

    public function getUserToken(): ?SoapVar
    {
        return $this->userToken;
    }

    public function setUserToken(SoapVar $userToken): self
    {
        $this->userToken = $userToken;
        return $this;
    }

    public function getEdiOrder() : ?SoapVar
    {
        return $this->ediOrder;
    }

    public function setEdiOrder(SoapVar $ediOrder): self
    {
        $this->ediOrder = $ediOrder;
        return $this;
    }

    public function getOrderLine(): ArrayObject
    {
        return $this->OrderLine;
    }

    public function attachOrderLine(SoapVar $orderLine): self
    {
        $this->orderLine->append($orderLine);
        return $this;
    }

    public function setOrderLine(ArrayObject $orderLine): self
    {
        $this->OrderLine = $orderLine;
        return $this;
    }
}
<?php
namespace Webservice\Entity;

class OrderLine 
{
    protected $AdditionalCustomerReferenceNumber;
    protected $LineID;
    protected $OrderedArticle;
    protected $PortalReference;

    // getters and setters here
}
<?php
namespace Wesbervice;
use Webservice\Entity\Order;
use Webservice\Entity\OrderLine;
use Webservice\Entity\PlaceOrder;
use SoapFault;
use SoapVar;

try {
    // this url contains the wrong defined PlaceOrder complex type
    $wsdl = 'https://uat-salesapi.ndias.com/service.svc?singlewsdl&version=27';

    $client = new SoapClient($wsdl, [
        'cache_wsdl' => WSDL_CACHE_NONE, // as long as you work on your wsdl
        'encoding' => 'utf-8',
        'exceptions' => true,
        'soap_version' => SOAP_1_1,
        'trace' => true, // enables tracing and __getLastRequest() / __getLastResponse()
        'classmap' => [
            'order' => Order::class,
            'OrderLine' => OrderLine::class,
            'PlaceOrder' => PlaceOrder::class,    
        ],
    ]);

    // user token
    $usertoken = new SoapVar('bla', XSD_STRING, '', '', 'userToken', 'http://tempuri.org/');

    // edi order
    $order = (new Order())
        ->setBlanketOrderReference(new SoapVar(...))
        ->setBuyerParty(new SoapVar(...);

    $order = new SoapVar($order, SOAP_ENC_OBJECT, '', '', 'ediOrder', 'http://tempuri.org/');

    // compile our request parameter
    $parameter = (new PlaceOrder())
        ->setUserToken($usertoken)
        ->setEdiOrder($order);

    // order list objects
    $orderLine1 = (new OrderLine())
        ->setAdditionalCustomerReferenceNumber(new SoapVar(...))
        ->setLineID(new SoapVar(...));

    $orderLine1 = new SoapVar($orderLine1, SOAP_ENC_OBJECT, '', '', 'OrderLine', 'http://tempuri.org/');

    $parameter->attachOrderLine($orderLine1);

    $orderLine2 = (new OrderLine())
        ->setAdditionalCustomerReferenceNumber(new SoapVar(...))
        ->setLineID(new SoapVar(...));

    $orderLine2 = new SoapVar($orderLine2, SOAP_ENC_OBJECT, '', '', 'OrderLine', 'http://tempuri.org/');

    $parameter->attachOrderLine($orderLine2);

    $parameter = new SoapVar($parameter, SOAP_ENC_OBJECT, '', '', 'PlaceOrder', 'http://tempuri.org/');

    // the client knows the PlaceOrder method from the wsdl
    $result = $client->PlaceOrder($parameter);

    // the result is a stdClass structure, als long as the classmap parameter does not contain definitions of type to php entity classes
    echo "<pre>";
    var_dump($result);
    echo "</pre>";
} catch (SoapFault $fault) {
    echo "<pre>";
    var_dump($fault);
    echo "</pre>";
}
public class Output
{
    [XmlElementAttribute("ResponseLineTest")]
    public OrderLn[] ResponseLine { get; set; }
}

public class OrderLn
{
    public string Order { get; set; }
}

[ServiceContract(Namespace = "Question59659046")]
[XmlSerializerFormat]
public interface IQuestion59659046Service
{
    [OperationContract]
    Output GetOutput(string input);
}
[ServiceContract(Namespace = "Question59659046")]
[XmlSerializerFormat]
public interface IQuestion59659046Service
{
    [OperationContract]
    Output GetOutput(string input);
}