views:

49

answers:

3

I have a XML documents (which describes a wsdl service's interface):

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"&gt;
  <wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/"&gt;
      <s:element name="GetDummyType">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="param1" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="GetDummyTypeResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="GetDummyTypeResult" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="SimplestWebService">
        <s:complexType />
      </s:element>
      <s:element name="SimplestWebServiceResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="SimplestWebServiceResult" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="SignInComp">
        <s:complexType />
      </s:element>
      <s:element name="SignInCompResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="SignInCompResult" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>

...

Two operations I need to perform on the above xml:

  1. retrieve all elements names (GetDummyType, SimplestWebService etc.) Those are the methods names (they don't end with "Response").
  2. retrieve a method's params by it's name (param1 for GetDummyType etc.)

I've managed so far only to parse this document as an XmlDocument:

XmlDocument doc = new XmlDocument();
doc.LoadXml(result.ToString());  

(I know that's not much)

I just can't figure out how that XML is mapped to something you can use linq on..
How do you do that?

Thanks.

+2  A: 

for #1, using the assembly System.Linq.Xml you could do sth like:

List<string> names = new List<string>();
XDocument doc = Xdocument.Parse(result.ToString());
foreach (XElement element in doc.Elements("wsdl:types").First().Elements("s:schema").First().Elements("s:element"))
{
    names.Add(element.Attributes("name").First().Value);
}

it isn't tested so you may have to tune a bit the code ;)

BTW, you may find more information on msdn concerning System.Xml.Linq

PierrOz
+3  A: 

You need to make sure to use correct XML namespaces in queries. Also, for LINQ to XML, use XDocument, not XmlDocument, which is from old System.Xml.

This is what I managed to come up with so far:

XDocument doc = XDocument.Parse(xml);
XNamespace wsdl = "http://schemas.xmlsoap.org/wsdl/";
XNamespace s = "http://www.w3.org/2001/XMLSchema";

var schema = doc.Root
    .Element(wsdl + "types")
    .Element(s + "schema");

var elements = schema.Elements(s + "element");
Func<XElement, string> getName = (el) => el.Attribute("name").Value;   

// these are all method names
var names = from el in elements
            let name = getName(el)
            where !name.EndsWith("Response")
            select name;

string methodName = "GetDummyType";
var method = elements
    .Single(el => getName(el) == methodName);

// these are all parameters for a given method
var parameters = from par in method.Descendants(s + "element")
                 select getName(par);

I have tested this code and it works on your data.
However I am not entirely it is the simplest solution there is so I welcome any suggestions to shortening the code.

Best,
Dan

gaearon
Just FYI: Minor glitch (returned some irrelevant method names) which I solved by : var methodsNamesElements = elements.Where(x => x.Descendants().Count() != 0); and quering over methodsNamesElements instead of elements. But other than that - works like a charm! thanks a lot.
Oren A
A: 

using linq to xml you can do something like this -

XDocument doc = XDocument.Parse( xmlstring );
var methods = from methods in doc.Descendants( "s:element" )
                where !methods.Attribute("name").Value.EndsWith("Resopnse")
                select methods;
        var methodNames = ( from method in methods
                            select method.Attribute( "name" ).Value ).ToList( );
        var paramList = from type in methods.Descendants( "s:complexType" )
                        from param in type.Descendants("s:sequence")
                        where type.HasElements && type.Parent.Attribute("name").Value == somemethodname   
                        select new { Name = param.Attribute( "name" ).Value };

add reference to system.core and system.xml.linq

Vinay B R
Hi! I would like to make some comments regarding your code. Firstly, you **cannot query for elements with namespaces by ns:element convention**. You need to specify namespaces explicitly, see MSDN: http://msdn.microsoft.com/en-us/library/bb387075.aspx. Secondly, why would you use Descendants several times on a method? If you want to reproduce hierarchy exactly, you should use Element(s) extension methods because they guarantee the structure is the same that you imagine it is. If not, method.Descendants("s:element") would return all method parameters anyways, even if they are deeper.
gaearon