Da Bazz
Da Bazz

Reputation: 61

Linq XML NullReference Exception on reading list of elements

I'm trying to read a list of Text nodes from my Xml file. When I try to read the children nodes of 1 of the listed text elements I get the NullReference exception, even though the XDocument nodes are seemingly filled. The NullReference exception is thrown on the line foreach (XElement textElement in textElements) this means that the list textElements has a Count > 1 so it shouldn't be null. That's as far as the debugger is willing to go.

Am I reading the Xml in the wrong way, or am I not allowed to / shouldn't build the XElement lists the way I am now?

This is my Xml file

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Book SYSTEM "Book.dtd"[]>
<album version="0.2" settingsVersion="1">
  <size />
  <cover />
  <inner>
    <page>
      <pagenumber>1</pagenumber>
      <image>1.jpg</image>
      <text>
        <value>Test </value>
        <font>arial</font>
        <size>18pt</size>
        <style>normal</style>
        <weight>normal</weight>
        <color>#77DD44</color>
        <rotation>0</rotation>
        <alignment>start</alignment>
        <position>
          <x>50</x>
          <y>50</y>
        </position>
      </text>
      <text>
          <value>Test 2 </value>
          <font>arial</font>
          <size>18pt</size>
          <style>normal</style>
          <weight>normal</weight>
          <color>#77DD44</color>
          <rotation>0</rotation>
          <alignment>start</alignment>
          <position>
             <x>50</x>
             <y>50</y>
          </position>
       </text>
    </page>
  </inner>
</album>

Element inner can hold multiple page elements and page can hold multiple text elements.

I read the Xml in the following method.

List<XElement> pageElements = doc.Root.Element("inner").Elements("page").ToList();
foreach (XElement pageElement in pageElements)
{
    string pageNumberString = pageElement.Element("pagenumber").Value;
    int pageNumberValue = Convert.ToInt32(pageNumberString);
    string fileNameValue = pageElement.Element("image").Value;
    // Verify if the currently looped page is the same as the one selected by the user.
    if (pageNumberValue == pageNumber)
    {
        // Get all text nodes from the found page.
        List<XElement> textElements = pageElement.Elements("text").ToList();
        // If no text nodes found return the page with an empty TextInfo array.
        if (textElements.Count == 0)
        {
            PageInfo pageInfoNoText = new PageInfo { PageNumber = pageNumberValue, FileName = fileNameValue, Text = new TextInfo[0] };
            Logger.log("PageInfo found for collection {0}. Info {1}", collectionId, pageInfoNoText);
            return pageInfoNoText;
        }
        // If text nodes are found build a list of TextInfo objects and build a new PageInfo object.
        else
        {
            // All text elements in the XML under the found page.
            List<TextInfo> textInfoList = new List<TextInfo>();
            TextInfo[] textArray = new TextInfo[0];

            #region  Load all required text data from the XML file and build the textList.
            foreach (XElement textElement in textElements)
            {
                string textValue = textElement.Element("value").Value;

                string fontValue = textElement.Element("font").Value;

                string fontSizeValue = textElement.Element("size").Value;

                string styleValue = textElement.Element("style").Value;

                string weightValue = textElement.Element("weight").Value;

                string colorValue = textElement.Element("color").Value;

                string rotationString = textElement.Element("rotation").Value;
                int rotationValue = Convert.ToInt32(rotationString);

                string alignmentValue = textElement.Element("alignment").Value;

                string positionXString = textElement.Element("x").Value;
                int positionXValue = Convert.ToInt32(positionXString);

                string positionYString = textElement.Element("y").Value;
                int positionYValue = Convert.ToInt32(positionYString);

                // Build Info objects.
                PositionInfo tempPositionInfo = new PositionInfo
                {
                    X = positionXValue,
                    Y = positionYValue
                };

                TextInfo tempTextInfo = new TextInfo
                {
                    Value = textValue,
                    Font = fontValue,
                    Size = fontSizeValue,
                    Style = styleValue,
                    Weight = weightValue,
                    Color = colorValue,
                    Rotation = rotationValue,
                    Alignment = alignmentValue,
                    Position = tempPositionInfo
                };

                textInfoList.Add(tempTextInfo);

            }
            textArray = textInfoList.ToArray();
            #endregion

            PageInfo pageInfo = new PageInfo
            {
                PageNumber = pageNumberValue,
                FileName = fileNameValue,
                Text = textArray
            };
            Logger.log("PageInfo found for collection {0}. Info: {1}", collectionId, pageInfo);
            return pageInfo;

        }
    }
}

Any help / insight is appreciated!

Upvotes: 1

Views: 49

Answers (2)

reckface
reckface

Reputation: 5858

your text element does not contain an element called x, so trying to access the value of x results in a NullReferenceException:

string positionXString = textElement.Element("x").Value;
// textElement.Element("x") is null, "x" is in textElement.Element("position")
int positionXValue = Convert.ToInt32(positionXString);

You might be better using Descendants (Descendants("x").FirstOrDefault()?.Value) instead of Element for this, but overall you may want to restructure this altogether.

Upvotes: 1

Damith
Damith

Reputation: 63065

your code is fine but there is a mistake when you get x and y values, you need to get x and y values of position element as below

string positionXString = (string)textElement.Element("position").Element("x").Value;
int positionXValue = Convert.ToInt32(positionXString);
string positionYString = (string)textElement.Element("position").Element("y").Value;
int positionYValue = Convert.ToInt32(positionYString);

Upvotes: 1

Related Questions