1

I have problem with properly using XPathSelectElement. I'm trying to find element in XML file by XPathSelectElement.

this.xdocument = XDocument.Parse (this.loadDialogues ());
XElement element = this.xdocument.XPathSelectElement ("/dialogues/npc[@npcid='1']/conversation[@id='1']/message[@mid='1']/options/option[@oid='1']/text()");

It is giving me this error:

NullReferenceException: Object reference not set to an instance of an object

But when I run for ex. this query:

XElement element = this.xdocument.XPathSelectElement ("/dialogues/npc");

Everything is ok. Can anyone tell me what is wrong? I can't find anything about this error in that context.

My XML example file:

<dialogues>
<!-- Greetings messages -->
<greetings>
    <friendly>
        <text id="1">Witaj przybyszu! W czym mogę Ci pomóc?</text>
        <text id="2">Aniele, co Cię do mnie sprowadza?</text>
        <text id="3">Witaj przybyszu! Czy szukasz czegoś konkretnego?</text>
    </friendly>
    <agressive>
        <text id="1">Czego chcesz? Nie mam ochoty rozmawiać więc się streszczaj.</text>
        <text id="2">Możesz mnie zostawić? To wszystko mnie przerasta...</text>
    </agressive>
</greetings>
<!-- Farewells -->
<farewells>
    <friendly>
        <text id="1">Żegnaj</text>
        <text id="2">Dziękuję, żegnaj</text>
        <text id="3">Do zobaczenia</text>
    </friendly>
    <agressive>
        <text id="1">***** z moich oczu, przybłędo</text>
        <text id="2">Odejdź stąd natychmiast, nie masz tu czego szukać</text>
    </agressive>
</farewells>
<!-- Monologs -->
<monologs>
    <monolog id="1">
        <text id="1">
            Monolog się rozpoczyna...
        </text>
        <text id="2">
            Monolog, część środkowa...
        </text>
        <text id="3">
            Monolog się kończy...
        </text>
    </monolog>
</monologs>
<!-- NPC -->
<npc npcid="1"> 
    <conversation id="1">
        <message mid="1" trigger="greetingRandom(friendly)">                
            <options>
                <option oid="1" nextmid="2">Tak, możesz mi powiedzieć gdzie znajdę Kaplicę?</option>
                <option trigger="endConversationRandom(friendly)"></option>
            </options>
        </message>
        <message mid="2">
            <text>Musisz pójść prosto, u dołu tych schodów będzie strażnik. Powiedz mu, żę Cię przysyłam, wtedy nie powinien robić problemów.</text>
            <options>
                <option oid="1" trigger="endConversation">Dziękuję, żegnaj.</option>
            </options>
        </message>
    </conversation>
</npc>

//EDIT: Full error with more info

NullReferenceException: Object reference not set to an instance of an object
System.Xml.Linq.XNodeNavigator.get_NodeType ()  
System.Xml.XPath.NodeTypeTest.Match (IXmlNamespaceResolver nsm, System.Xml.XPath.XPathNavigator nav)  
System.Xml.XPath.AxisIterator.MoveNextCore ()  
System.Xml.XPath.BaseIterator.MoveNext ()  
System.Xml.XPath.SimpleSlashIterator.MoveNextCore ()  
System.Xml.XPath.BaseIterator.MoveNext ()  
System.Xml.XPath.SlashIterator.MoveNextCore ()  
System.Xml.XPath.BaseIterator.MoveNext ()  
System.Xml.XPath.SortedIterator..ctor (System.Xml.XPath.BaseIterator iter)  
System.Xml.XPath.ExprSLASH2.Evaluate (System.Xml.XPath.BaseIterator iter)  
System.Xml.XPath.Expression.EvaluateNodeSet (System.Xml.XPath.BaseIterator iter)  
System.Xml.XPath.CompiledExpression.EvaluateNodeSet (System.Xml.XPath.BaseIterator iter)  
System.Xml.XPath.XPathNavigator.Select (System.Xml.XPath.XPathExpression expr, IXmlNamespaceResolver ctx)  
System.Xml.XPath.XPathNavigator.Select (System.Xml.XPath.XPathExpression expr)  
System.Xml.XPath.XPathNavigator.SelectSingleNode (System.Xml.XPath.XPathExpression expression)  
System.Xml.XPath.XPathNavigator.SelectSingleNode (System.String xpath, IXmlNamespaceResolver nsResolver)  
System.Xml.XPath.Extensions.XPathSelectElement (System.Xml.Linq.XNode node, System.String xpath, IXmlNamespaceResolver nsResolver)  
System.Xml.XPath.Extensions.XPathSelectElement (System.Xml.Linq.XNode node, System.String xpath)  
DialogueParser.getConversation (Int32 npcID, Int32 conversationID) (at Assets/Dedicated Assets/Scripts/Dialogue/DialogueParser.cs:38)  
DialogueManager.Awake () (at Assets/Dedicated Assets/Scripts/Dialogue/DialogueManager.cs:33)
Narkon
  • 398
  • 2
  • 17
  • Possible duplicate of [What is a NullReferenceException and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Kevin Dec 17 '15 at 19:08
  • I bet that if you were to debug to this spot in your code the `null` reference exception is actually happening on a different line where `element` is being used. If your path doesn't find an element it will return null, then when you try to call a property or function on that null object it will throw the exception – Kevin Dec 17 '15 at 19:10

2 Answers2

0

It is called XPathSelectElement because it allows you to select element nodes. Your path ending with text() tries to select a text node, so you will always get a null XElement reference as your path does not select any element node. So use a path selecting an element node and not a text node.

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Thanks for reponse. I'm getting the same error even if I'm trying to search with this xpath: `/dialogues/npc[@npcid='1']` – Narkon Dec 17 '15 at 19:34
  • Works fine for me, see https://dotnetfiddle.net/HuNLpC. Try to post minimal but complete samples allowing us to reproduce the problem. – Martin Honnen Dec 17 '15 at 19:44
  • It's my whole class: http://pastebin.com/MWKAEnYW I fix this error but for now my `element` is `null` - line 32 in my class – Narkon Dec 17 '15 at 19:53
  • Well then log the XML as well and we can tell you the reason. – Martin Honnen Dec 17 '15 at 20:03
  • Hmm, it's so strange. When I'm casting it in this way: `XElement el = this.xdocument.XPathSelectElement (".//dialogues").XPathSelectElement (".//npc");` it's working, but when I'm trying to cast it in one query and with id's for ex. `XElement el = this.xdocument.XPathSelectElement (".//dialogues/npc[@npcid='1']");` It cast the error: `NullReferenceException: Object reference not set to an instance of an object System.Xml.Linq.XNodeNavigator.get_NodeType ()` I'm sure that the XML file is loaded correctly to the `XDocument.Parse()` method... – Narkon Dec 17 '15 at 23:57
0

Finally I solved the problem by using XMLDocument instead of XDocument.

In Unity3D is something wrong with System.Xml.XPath.

public class DialogueParser {

    /// <summary>
    /// XMLDocument Instance
    /// </summary>
    private XmlDocument xmldocument;

    public DialogueParser()
    {
        //Populate XMLDocument Instance
        this.xmldocument = new XmlDocument ();
        this.xmldocument.LoadXml (this.loadDialogues());
    }

    /// <summary>
    /// Loads the dialogues from file into TextStream.
    /// </summary>
    /// <returns>dialogues.xml content as text for parsing</returns>
    public string loadDialogues()
    {
        TextAsset dialogues = (TextAsset) Resources.Load<TextAsset> ("dialogues");
        return dialogues.text;
    }

    public void getConversation(int npcID, int conversationID)
    {
        XmlNode el = this.xmldocument.SelectSingleNode (".//dialogues/npc[@npcid='1']/conversation[@id='1']/message[@mid='2']/text/text()");
        Debug.Log (el.Value);
    }
}

With XMLDocument all is fine so I recommend using it instead of XDocument for reading XML Files.

Narkon
  • 398
  • 2
  • 17