Search code examples
xmlxpath

Why is an XPath expression returning an element with just one child?


I have this XML file. It contains C# documentation comments exported by MSBuild (if that's relevant).

<?xml version="1.0"?>
<doc>
  <assembly>
    <name>Test</name>
  </assembly>
  <members>
    <member name="T:Test.TestClass`2">
      <summary>
        This is just a test class.
      </summary>
      <typeparam name="T1">A generic parameter.</typeparam>
      <typeparam name="T2">Another generic parameter.</typeparam>
      <remarks>
        It is used to test the library.

        <typeparamref name="T1"/> is a very nice generic parameter.
      </remarks>
      <seealso>
        Don't see also
      </seealso>
    </member>
    <member name="P:Test.TestClass`2.TestProperty">
      <summary>
        This is a property of the <see cref="T:Test.TestClass"/> class.
      </summary>
      <value>
        Always returns 0.
      </value>
      <seealso>
        Don't see also
      </seealso>
    </member>
    <member name="M:Test.TestClass`2.Generic`1(System.Int32,System.Collections.Generic.List{`0},System.Collections.Generic.List{`3})">
      <summary>
        Test of the generic parameters handling.
      </summary>
    </member>
    <member name="M:Test.TestClass`2.DoTheJob(System.String,System.Int32)">
      <param name="str">A string.</param>
      <param name="integer">A 32-bit integer.</param>
      <remarks>
        A dummy method. Don't pass 3 to <paramref name="integer"/>.
      </remarks>
    </member>
    <member name="T:Test.AnotherTestClass">
      <summary>
        A nice little class.
      </summary>
    </member>
    <member name="E:Test.AnotherTestClass.MyEvent">
      <summary>
        Occurs very frequently.
      </summary>
      <example>
        anotherTestClass.MyEvent += MyHandler;
      </example>
    </member>
    <member name="F:Test.AnotherTestClass.StructureOfTheWorld">
      Some idiot put this text here.
      <summary>
        Contains the <c>structure</c> of the world.
      </summary>
      <remarks>
        Includes:

        <list type="bullet">
          <item>
            <term>Stars</term>
            <description>Large shining spheres</description>
          </item>
          <item>
            <term>Planets</term>
            <description>Smaller spheres that go around stars</description>
          </item>
          <item>
            <term>Planets</term>
            <description>Smaller spheres that go around stars</description>
          </item>
          <item>
            <term>Black holes</term>
            <description>Very curious objects</description>
          </item>
        </list>
      </remarks>
    </member>
    <member name="M:Test.AnotherTestClass.#ctor(System.Type)">
      <summary>
        This is a constructor.
      </summary>
      <seealso>
        <list type="bullet">
          <item>I</item>
          <item>Mum</item>
          <item>Dad</item>
          <item>Grandad</item>
          <item>Grandma</item>
          <item>Brother</item>
          <item>Sister</item>
        </list>
      </seealso>
    </member>
    <member name="M:Test.AnotherTestClass.op_Implicit(Test.AnotherTestClass)~System.String">
      <summary>
        Just calls ToString().
      </summary>
      <remarks>
        Do not use.
      </remarks>
    </member>
  </members>
</doc>

I want to inspect member elements one-by-one, searching them by names. I'm using this XPath expression:

//member[@name='{insert_name_to_be_inspected_here}']

which works, but for some curious reason the member element it returns only has one child element, even if there are more.

If I search for T:Test.AnotherTestClass, it returns this XML (the indents are copied precisely):

<summary>
        A nice little class.
      </summary>

If I search for T:Test.TestClass`2, it returns this:

<summary>
        This is just a test class.
      </summary>

So where are the remarks, typeparam etc elements?


Solution

  • A minimal reproducible example is not provided. So, I am shooting from the hip.

    Please find below a solution based on LINQ to XML API. It is available in the .Net Framework since 2007.

    c#

    void Main()
    {
        const string xmlFile = @"e:\Temp\SNBS.xml";
        string memeberName = "T:Test.TestClass`2";
        
        XDocument xdoc = XDocument.Load(xmlFile);
    
        var xelem = xdoc.Descendants("member")
          .Where(x => x.Attribute("name").Value == memeberName);
          
        Console.WriteLine(xelem);
    }
    

    Output

    <member name="T:Test.TestClass`2">
      <summary>This is just a test class.</summary>
      <typeparam name="T1">A generic parameter.</typeparam>
      <typeparam name="T2">Another generic parameter.</typeparam>
      <remarks>It is used to test the library.
    
                    <typeparamref name="T1" />is a very nice generic parameter.</remarks>
      <seealso>Don't see also</seealso>
    </member>