Index: applications/editors/josm/plugins/opendata/includes/org/apache/poi/hssf/usermodel/HSSFRow.java
===================================================================
--- applications/editors/josm/plugins/opendata/includes/org/apache/poi/hssf/usermodel/HSSFRow.java	(revision 34071)
+++ applications/editors/josm/plugins/opendata/includes/org/apache/poi/hssf/usermodel/HSSFRow.java	(revision 34072)
@@ -18,11 +18,7 @@
 package org.apache.poi.hssf.usermodel;
 
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
 import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.RowRecord;
 import org.apache.poi.ss.SpreadsheetVersion;
-import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
 
@@ -102,4 +98,5 @@
      *   the maximum number of columns supported by the Excel binary format (.xls)
      */
+    @Override
     public HSSFCell createCell(int column)
     {
@@ -119,4 +116,5 @@
      *   the maximum number of columns supported by the Excel binary format (.xls)
      */
+    @Override
     public HSSFCell createCell(int columnIndex, int type)
     {
@@ -164,4 +162,5 @@
      * @throws IndexOutOfBoundsException if the row number is not within the range 0-65535.
      */
+    @Override
     public void setRowNum(int rowIndex) {
         int maxrow = SpreadsheetVersion.EXCEL97.getLastRowIndex();
@@ -180,4 +179,5 @@
      * @return the row number (0 based)
      */
+    @Override
     public int getRowNum()
     {
@@ -190,9 +190,9 @@
      * @return the HSSFSheet that owns this row
      */
+    @Override
     public HSSFSheet getSheet()
     {
         return sheet;
     }
-
 
     /**
@@ -240,5 +240,4 @@
     }
 
-
     /**
      * Get the hssfcell representing a given column (logical cell)
@@ -250,4 +249,5 @@
      * @return HSSFCell representing that column or null if undefined.
      */
+    @Override
     public HSSFCell getCell(int cellnum) {
         return getCell(cellnum, book.getMissingCellPolicy());
@@ -263,4 +263,5 @@
      * @return representing that column or null if undefined + policy allows.
      */
+    @Override
     public HSSFCell getCell(int cellnum, MissingCellPolicy policy) {
         HSSFCell cell = retrieveCell(cellnum);
@@ -285,4 +286,31 @@
 
     /**
+     * Gets the index of the last cell contained in this row <b>PLUS ONE</b>. The result also
+     * happens to be the 1-based column number of the last cell.  This value can be used as a
+     * standard upper bound when iterating over cells:
+     * <pre>
+     * short minColIx = row.getFirstCellNum();
+     * short maxColIx = row.getLastCellNum();
+     * for(short colIx=minColIx; colIx&lt;maxColIx; colIx++) {
+     *   HSSFCell cell = row.getCell(colIx);
+     *   if(cell == null) {
+     *     continue;
+     *   }
+     *   //... do something with cell
+     * }
+     * </pre>
+     *
+     * @return short representing the last logical cell in the row <b>PLUS ONE</b>, or -1 if the
+     *  row does not contain any cells.
+     */
+    @Override
+    public short getLastCellNum() {
+        if (row.isEmpty()) {
+            return -1;
+        }
+        return (short) row.getLastCol();
+    }
+
+    /**
      * get the lowlevel RowRecord represented by this object - should only be called
      * by other parts of the high level API
@@ -290,5 +318,4 @@
      * @return RowRecord this row represents
      */
-
     protected RowRecord getRowRecord()
     {
@@ -296,68 +323,5 @@
     }
 
-    /**
-     * @return cell iterator of the physically defined cells.
-     * Note that the 4th element might well not be cell 4, as the iterator
-     *  will not return un-defined (null) cells.
-     * Call getCellNum() on the returned cells to know which cell they are.
-     * As this only ever works on physically defined cells,
-     *  the {@link org.apache.poi.ss.usermodel.Row.MissingCellPolicy} has no effect.
-     */
-    public Iterator<Cell> cellIterator()
-    {
-      return new CellIterator();
-    }
-    /**
-     * Alias for {@link #cellIterator} to allow
-     *  foreach loops
-     */
-    public Iterator<Cell> iterator() {
-       return cellIterator();
-    }
-
-    /**
-     * An iterator over the (physical) cells in the row.
-     */
-    private class CellIterator implements Iterator<Cell> {
-      int thisId=-1;
-      int nextId=-1;
-
-      public CellIterator()
-      {
-        findNext();
-      }
-
-      public boolean hasNext() {
-        return nextId<cells.length;
-      }
-
-      public Cell next() {
-          if (!hasNext())
-              throw new NoSuchElementException("At last element");
-        HSSFCell cell=cells[nextId];
-        thisId=nextId;
-        findNext();
-        return cell;
-      }
-
-      public void remove() {
-          if (thisId == -1)
-              throw new IllegalStateException("remove() called before next()");
-        cells[thisId]=null;
-      }
-
-      private void findNext()
-      {
-        int i=nextId+1;
-        for(;i<cells.length;i++)
-        {
-          if(cells[i]!=null) break;
-        }
-        nextId=i;
-      }
-
-    }
-
-
+    @Override
     public boolean equals(Object obj)
     {
Index: applications/editors/josm/plugins/opendata/includes/org/apache/poi/ss/usermodel/Row.java
===================================================================
--- applications/editors/josm/plugins/opendata/includes/org/apache/poi/ss/usermodel/Row.java	(revision 34071)
+++ applications/editors/josm/plugins/opendata/includes/org/apache/poi/ss/usermodel/Row.java	(revision 34072)
@@ -18,10 +18,8 @@
 package org.apache.poi.ss.usermodel;
 
-import java.util.Iterator;
-
 /**
  * High level representation of a row of a spreadsheet.
  */
-public interface Row extends Iterable<Cell> {
+public interface Row {
 
     /**
@@ -75,5 +73,5 @@
      */
     Cell getCell(int cellnum);
-    
+
     /**
      * Returns the cell at the given (0 based) index, with the specified {@link org.apache.poi.ss.usermodel.Row.MissingCellPolicy}
@@ -88,8 +86,23 @@
 
     /**
-     * @return Cell iterator of the physically defined cells.  Note element 4 may
-     * actually be row cell depending on how many are defined!
+     * Gets the index of the last cell contained in this row <b>PLUS ONE</b>. The result also
+     * happens to be the 1-based column number of the last cell.  This value can be used as a
+     * standard upper bound when iterating over cells:
+     * <pre>
+     * short minColIx = row.getFirstCellNum();
+     * short maxColIx = row.getLastCellNum();
+     * for(short colIx=minColIx; colIx&lt;maxColIx; colIx++) {
+     *   Cell cell = row.getCell(colIx);
+     *   if(cell == null) {
+     *     continue;
+     *   }
+     *   //... do something with cell
+     * }
+     * </pre>
+     *
+     * @return short representing the last logical cell in the row <b>PLUS ONE</b>,
+     *   or -1 if the row does not contain any cells.
      */
-    Iterator<Cell> cellIterator();
+    short getLastCellNum();
 
     /**
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/XlsReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/XlsReader.java	(revision 34071)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/XlsReader.java	(revision 34072)
@@ -58,24 +58,30 @@
             if (row != null) {
                 List<String> result = new ArrayList<>();
-                for (Cell cell : row) {
-                    switch (cell.getCellType()) {
-                        case Cell.CELL_TYPE_STRING:
-                            result.add(cell.getRichStringCellValue().getString());
-                            break;
-                        case Cell.CELL_TYPE_NUMERIC:
-                            if (DateUtil.isCellDateFormatted(cell)) {
-                                result.add(cell.getDateCellValue().toString());
-                            } else {
-                                result.add(Double.toString(cell.getNumericCellValue()));
-                            }
-                            break;
-                        case Cell.CELL_TYPE_BOOLEAN:
-                            result.add(Boolean.toString(cell.getBooleanCellValue()));
-                            break;
-                        case Cell.CELL_TYPE_FORMULA:
-                            result.add(cell.getCellFormula());
-                            break;
-                        default:
-                            result.add("");
+                // Do not use iterator! It skips null values
+                for (int i = 0; i < row.getLastCellNum(); i++) {
+                    Cell cell = row.getCell(i);
+                    if (cell != null) {
+                        switch (cell.getCellType()) {
+                            case Cell.CELL_TYPE_STRING:
+                                result.add(cell.getRichStringCellValue().getString());
+                                break;
+                            case Cell.CELL_TYPE_NUMERIC:
+                                if (DateUtil.isCellDateFormatted(cell)) {
+                                    result.add(cell.getDateCellValue().toString());
+                                } else {
+                                    result.add(Double.toString(cell.getNumericCellValue()));
+                                }
+                                break;
+                            case Cell.CELL_TYPE_BOOLEAN:
+                                result.add(Boolean.toString(cell.getBooleanCellValue()));
+                                break;
+                            case Cell.CELL_TYPE_FORMULA:
+                                result.add(cell.getCellFormula());
+                                break;
+                            default:
+                                result.add("");
+                        }
+                    } else {
+                        result.add("");
                     }
                 }
Index: applications/editors/josm/plugins/opendata/test/unit/org/openstreetmap/josm/plugins/opendata/core/io/tabular/XlsReaderTest.java
===================================================================
--- applications/editors/josm/plugins/opendata/test/unit/org/openstreetmap/josm/plugins/opendata/core/io/tabular/XlsReaderTest.java	(revision 34072)
+++ applications/editors/josm/plugins/opendata/test/unit/org/openstreetmap/josm/plugins/opendata/core/io/tabular/XlsReaderTest.java	(revision 34072)
@@ -0,0 +1,82 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.opendata.core.io.tabular;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLStreamException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.projection.Projections;
+import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.NonRegFunctionalTests;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+/**
+ * Unit tests of {@link XlsReader} class.
+ */
+public class XlsReaderTest {
+
+    /**
+     * Setup test.
+     */
+    @Rule
+    public JOSMTestRules rules = new JOSMTestRules().preferences().projection();
+
+    private static AbstractDataSetHandler newHandler(final String epsgCode) {
+        AbstractDataSetHandler handler = new AbstractDataSetHandler() {
+            @Override
+            public boolean acceptsFilename(String filename) {
+                return true;
+            }
+
+            @Override
+            public void updateDataSet(DataSet ds) {
+            }
+        };
+        handler.setSpreadSheetHandler(new DefaultSpreadSheetHandler() {
+            @Override
+            public boolean handlesProjection() {
+                return true;
+            }
+
+            @Override
+            public LatLon getCoor(EastNorth en, String[] fields) {
+                return Projections.getProjectionByCode(epsgCode).eastNorth2latlon(en);
+            }
+        });
+        return handler;
+    }
+
+    /**
+     * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/15980">#15980</a>
+     * @throws IOException if an error occurs during reading
+     */
+    @Test
+    public void testTicket15980() throws IOException, XMLStreamException, FactoryConfigurationError {
+        try (InputStream is = TestUtils.getRegressionDataStream(15980, "qry_OSM_Import_Orte.xls")) {
+            DataSet ds = XlsReader.parseDataSet(is, newHandler("EPSG:4326"), null);
+            NonRegFunctionalTests.testGeneric("#15980", ds);
+            doTest15980(ds, "Straße 19", "19", null);
+            doTest15980(ds, "Straße 20", "20", null);
+            doTest15980(ds, "Straße", null, "highway");
+        }
+    }
+
+    private static void doTest15980(DataSet ds, String name, String addr, String fixme) {
+        OsmPrimitive osm = ds.getPrimitives(o -> name.equals(o.get("name"))).iterator().next();
+        assertNotNull(name, osm);
+        assertEquals(addr, osm.get("addr:housenumber"));
+        assertEquals(fixme, osm.get("fixme"));
+    }
+}
