为什么我在运行StAX解析器时会得到空指针异常?

huangapple go评论79阅读模式
英文:

Why I get NullPointerException when running StAX Parser?

问题

我试图在Java中编写一个StAX XML解析器但总是遇到NullPointerException错误请帮我解决这个问题完整的问题

> Exception in thread "main" java.lang.NullPointerException
> 	at org.example.shoesshop.parser.STAXParser.parseXMLfile(STAXParser.java:68)
> 	at org.example.shoesshop.parser.STAXParser.main(STAXParser.java:101)

这是一个用于StAX解析器的类

public class STAXParser extends DefaultHandler {
    private static List<Shoes> parseXMLfile(String fileName) {
        // ...
        //(原始代码)
        // ...
    }

    public static void main(String[] args) throws Exception {
        // ...
        //(原始代码)
        // ...
    }
}

这是一个XML文件的示例

<?xml version="1.0" encoding="UTF-8"?>
<!---->
</ss:ShoesShop>

这是一个用于鞋子的Java类

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Shoes", propOrder = {
    "title",
    "brand",
    //(略)
})
public class Shoes extends Entity {
    // ...
    //(原始代码)
    // ...
}

我还需要知道如何将接收到的数据写入新的XML文件

如果您有关于如何将接收到的数据写入新的XML文件的更多问题,请随时提问。

英文:

I'm trying to write a StAX XML Parser in Java, but always get NullPointerException error. Please help me to solve this issue. Full problem:

> Exception in thread "main" java.lang.NullPointerException at
> org.example.shoesshop.parser.STAXParser.parseXMLfile(STAXParser.java:68)
> at org.example.shoesshop.parser.STAXParser.main(STAXParser.java:101)

Here's a class for StAX Parser:

public class STAXParser extends DefaultHandler {
	private static List&lt;Shoes&gt; parseXMLfile(String fileName){
		List&lt;Shoes&gt; shoesList = new ArrayList&lt;&gt;();
		Shoes shoes = null;
		XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
		try {
			XMLEventReader reader = xmlInputFactory.createXMLEventReader(new FileInputStream(fileName));
			while (reader.hasNext()){
				XMLEvent xmlEvent = reader.nextEvent();
				if(xmlEvent.isStartElement()){
					StartElement startElement = xmlEvent.asStartElement();
					if(startElement.getName().getLocalPart().equals(&quot;Shoes&quot;)){
						shoes = new Shoes();
						Attribute idAttr = startElement.getAttributeByName(new QName(&quot;id&quot;));
						if(idAttr != null){
							shoes.setId(Integer.parseInt(idAttr.getValue()));
						}
					} else if (startElement.getName().getLocalPart().equals(&quot;title&quot;)){
						xmlEvent = reader.nextEvent();
						shoes.setTitle(xmlEvent.asCharacters().getData()); // error line 68
					} else if (startElement.getName().getLocalPart().equals(&quot;brand&quot;)){
						xmlEvent = reader.nextEvent();
						shoes.setBrand(Brand.fromValue(xmlEvent.asCharacters().getData()));
					} else if (startElement.getName().getLocalPart().equals(&quot;category&quot;)){
						xmlEvent = reader.nextEvent();
						shoes.setCategory(Category.fromValue(xmlEvent.asCharacters().getData()));
					} else if (startElement.getName().getLocalPart().equals(&quot;season&quot;)){
						xmlEvent = reader.nextEvent();
						shoes.setSeason(Season.fromValue(xmlEvent.asCharacters().getData()));
					} else if (startElement.getName().getLocalPart().equals(&quot;price&quot;)){
						xmlEvent = reader.nextEvent();
						shoes.setPrice(Double.parseDouble(xmlEvent.asCharacters().getData()));
					}
				}
				if(xmlEvent.isEndElement()){
					EndElement endElement = xmlEvent.asEndElement();
					if(endElement.getName().getLocalPart().equals(&quot;Shoes&quot;)){
						shoesList.add(shoes);
					}
				}
			}
		} catch (FileNotFoundException | XMLStreamException exc) {
			exc.printStackTrace();
		} return shoesList;
	}

	public static void main(String[] args) throws Exception {
		System.out.println(&quot;STAX Parser&quot;);
		System.out.println();
		System.out.println(&quot;Result: \n&quot;);
		System.out.println();
		String fileName = &quot;ShoesShop.xml&quot;;
		List&lt;Shoes&gt; shoesList = parseXMLfile(fileName); //error line 101
		for (Shoes shoes:shoesList){
			System.out.println(shoes.toString());
		}
	}

}

Here's an XML-file

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;?xml-stylesheet type = &quot;text/xsl&quot; href = &quot;ShoesShop.xsl&quot;?&gt;

&lt;ss:ShoesShop xmlns:ss=&quot;http://www.example.org/ShoesShop&quot; 
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; 
xsi:schemaLocation=&quot;http://www.example.org/ShoesShop ShoesShop.xsd &quot;&gt;
  &lt;ss:shoes id=&quot;1&quot; stock=&quot;true&quot;&gt;
    &lt;ss:title&gt;Baltrum&lt;/ss:title&gt;
    &lt;ss:brand&gt;Gucci&lt;/ss:brand&gt;
    &lt;ss:category&gt;Boots&lt;/ss:category&gt;
    &lt;ss:season&gt;fall&lt;/ss:season&gt;
    &lt;ss:gender&gt;
      &lt;ss:male&gt;male&lt;/ss:male&gt;
    &lt;/ss:gender&gt;
    &lt;ss:details&gt;
      &lt;ss:highlights&gt;Highlights text 1&lt;/ss:highlights&gt;
      &lt;ss:composition&gt;Composition text 1&lt;/ss:composition&gt;
    &lt;/ss:details&gt;
    &lt;ss:price&gt;734.0&lt;/ss:price&gt;
  &lt;/ss:shoes&gt;
  
  
  &lt;ss:shoes id=&quot;2&quot; stock=&quot;true&quot; mostWanted = &quot;true&quot;&gt;
    &lt;ss:title&gt;Amalfi&lt;/ss:title&gt;
    &lt;ss:brand&gt;Dior&lt;/ss:brand&gt;
    &lt;ss:category&gt;Mules&lt;/ss:category&gt;
    &lt;ss:season&gt;winter&lt;/ss:season&gt;
    &lt;ss:gender&gt;
      &lt;ss:female&gt;female&lt;/ss:female&gt;
    &lt;/ss:gender&gt;
    &lt;ss:details&gt;
      &lt;ss:highlights&gt;Highlights text 2&lt;/ss:highlights&gt;
      &lt;ss:composition&gt;Composition text 2&lt;/ss:composition&gt;
    &lt;/ss:details&gt;
    &lt;ss:price&gt;364.0&lt;/ss:price&gt;
  &lt;/ss:shoes&gt;
  
  &lt;ss:shoes id=&quot;3&quot; stock=&quot;true&quot; mostWanted = &quot;true&quot;&gt;
    &lt;ss:title&gt;Korfu&lt;/ss:title&gt;
    &lt;ss:brand&gt;Mary Katrantzou&lt;/ss:brand&gt;
    &lt;ss:category&gt;Sneakers&lt;/ss:category&gt;
    &lt;ss:season&gt;spring&lt;/ss:season&gt;
    &lt;ss:gender&gt;
      &lt;ss:female&gt;female&lt;/ss:female&gt;
    &lt;/ss:gender&gt;
    &lt;ss:details&gt;
      &lt;ss:highlights&gt;Highlights text 3&lt;/ss:highlights&gt;
      &lt;ss:composition&gt;Composition text 3&lt;/ss:composition&gt;
    &lt;/ss:details&gt;
    &lt;ss:price&gt;173.0&lt;/ss:price&gt;
  &lt;/ss:shoes&gt;
&lt;/ss:ShoesShop&gt;

Also here's a Java class for Shoes

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = &quot;Shoes&quot;, propOrder = {
    &quot;title&quot;,
    &quot;brand&quot;,
    &quot;category&quot;,
    &quot;season&quot;,
    &quot;gender&quot;,
    &quot;details&quot;,
    &quot;price&quot;
})
public class Shoes
    extends Entity
{
    @XmlElement(required = true)
    protected String title;
    @XmlElement(required = true)
    @XmlSchemaType(name = &quot;string&quot;)
    protected Brand brand;
    @XmlElement(required = true)
    @XmlSchemaType(name = &quot;string&quot;)
    protected Category category;
    @XmlElement(required = true)
    @XmlSchemaType(name = &quot;string&quot;)
    protected Season season;
    @XmlElement(required = true)
    protected Shoes.Gender gender;
    @XmlElement(required = true)
    protected Shoes.Details details;
    protected double price;
    @XmlAttribute(name = &quot;stock&quot;, required = true)
    protected boolean stock;
    @XmlAttribute(name = &quot;mostWanted&quot;)
    protected Boolean mostWanted;

    public String getTitle() {
        return title;
    }

    public void setTitle(String value) {
        this.title = value;
    }
    
    public Brand getBrand(){
    	return brand;
    }
    
    public void setBrand(Brand value){
    	this.brand = value;
    }
    
    public Category getCategory(){
    	return category;
    }
    
    public void setCategory(Category value){
    	this.category = value;
    }
    
    public Season getSeason(){
    	return season;
    }
    
    public void setSeason(Season value) {
    	this.season = value;
    }

    public Shoes.Gender getGender() {
        return gender;
    }

    public void setGender(Shoes.Gender value) {
        this.gender = value;
    }

    public Shoes.Details getDetails() {
        return details;
    }

    public void setDetails(Shoes.Details value) {
        this.details = value;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double value) {
        this.price = value;
    }

    public boolean isStock() {
        return stock;
    }

    public void setStock(boolean value) {
        this.stock = value;
    }

    public Boolean isMostWanted() {
        return mostWanted;
    }

    public void setMostWanted(Boolean value) {
        this.mostWanted = value;
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = &quot;&quot;, propOrder = {

    })
    public static class Details {

        @XmlElement(required = true)
        protected String highlights;
        @XmlElement(required = true)
        protected String composition;

        public String getHighlights() {
            return highlights;
        }

        public void setHighlights(String value) {
            this.highlights = value;
        }

        public String getComposition() {
            return composition;
        }

        public void setComposition(String value) {
            this.composition = value;
        }

    }

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = &quot;&quot;, propOrder = {
        &quot;\u043c\u0443\u0436\u0441\u043a\u043e\u0439Or\u0416\u0435\u043d\u0441\u043a\u0438\u0439&quot;
    })
    public static class Gender {

        @XmlElementRefs({
            @XmlElementRef(name = &quot;\u0436\u0435\u043d\u0441\u043a\u0438\u0439&quot;, namespace = &quot;http://www.example.org/ShoesShop&quot;, type = JAXBElement.class, required = false),
            @XmlElementRef(name = &quot;\u043c\u0443\u0436\u0441\u043a\u043e\u0439&quot;, namespace = &quot;http://www.example.org/ShoesShop&quot;, type = JAXBElement.class, required = false)
        })
        protected List&lt;JAXBElement&lt;String&gt;&gt; maleOrFemale;

        public List&lt;JAXBElement&lt;String&gt;&gt; getMaleOrFemale() {
            if (maleOrFemale == null) {
                maleOrFemale = new ArrayList&lt;JAXBElement&lt;String&gt;&gt;();
            }
            return this.maleOrFemale;
        }

    }
    
    @Override
    public String toString(){
    	StringBuilder builder = new StringBuilder();
    	builder.append(&quot;[title=&quot;);
    	builder.append(title);
    	builder.append(&quot;, brand=&quot;);
    	builder.append(brand);
    	builder.append(&quot;, category=&quot;);
    	builder.append(category);
    	builder.append(&quot;, season=&quot;);
    	builder.append(season);
    	builder.append(&quot;, price=&quot;);
    	builder.append(price);
    	builder.append(&quot;]&quot;);
    	return builder.toString();
    }

}

Also I need to know how to write a received data into a new XML-file.

答案1

得分: 1

UPDATED: 对原回答的评论:

它不起作用,仍然显示相同的错误

这意味着问题是因为 shoes 变量是 null,很容易通过调试器看到。使用调试器可以节省我们很多时间,所以请开始使用一个。

为了让 shoes 变量为 null,看起来代码遇到了一个不是 Shoes 元素的子元素的 <title> 元素。

要修复代码,在处理完 Shoes 元素后,添加一个空值检查,并且在代码末尾设置 shoes = null

} else if (startElement.getName().getLocalPart().equals("title")) {
    if (shoes != null) { // <===== 添加这一行
        shoes.setTitle(reader.getElementText()); // <===== 修复这一行(参见原始回答)
    }
}
if (xmlEvent.isEndElement()) {
    EndElement endElement = xmlEvent.asEndElement();
    if (endElement.getName().getLocalPart().equals("Shoes")) {
        shoesList.add(shoes);
        shoes = null; // <===== 添加这一行
    }
}

原始回答

您的代码是:

} else if (startElement.getName().getLocalPart().equals("title")){
    xmlEvent = reader.nextEvent();
    shoes.setTitle(xmlEvent.asCharacters().getData());

问题是代码没有检查 START_ELEMENT 事件之后的事件类型。可能是:

  • 最有可能的情况是元素是空的,即 &lt;title/&gt;&lt;title&gt;&lt;title/&gt;,在这种情况下,下一个事件是 END_ELEMENT,而 asCharacters() 返回了 null

  • 该元素有注释,例如 &lt;title&gt;&lt;!-- 没有标题 --&gt;&lt;title/&gt;,在这种情况下,下一个事件是 COMMENT

  • 该元素具有混合内容,例如 &lt;title&gt;foo&lt;![CDATA[bar]]&gt;&lt;title/&gt;,在这种情况下,下一个事件不是完整的文本。

检索元素的文本内容是一种常见的操作,因此他们为此添加了一个辅助方法:getElementText()

读取仅包含文本的元素的内容。前提条件:当前事件是 START_ELEMENT。后置条件:当前事件是相应的 END_ELEMENT

抛出:
XMLStreamException - 如果当前事件不是 START_ELEMENT,或者如果遇到非文本元素

这意味着您的代码应该是:

} else if (startElement.getName().getLocalPart().equals("title")) {
    shoes.setTitle(reader.getElementText());
英文:

UPDATED: Comment to original answer:

> It doesn't work, it gives the same error

That means the problem is because the shoes variable is null, as would have easily been seen with a debugger. Using a debugger would have saved us all a lot of time, so please start using one.

In order for shoes to be null, it appears that the code encountered a &lt;title&gt; element that is not a child of a Shoes element.

To fix the code, add a null-check, and also set shoes = null at the end of processing the Shoes element:

} else if (startElement.getName().getLocalPart().equals(&quot;title&quot;)) {
    if (shoes != null) { // &lt;===== ADD THIS
        shoes.setTitle(reader.getElementText()); // &lt;===== Fix this (see original answer)
    }
if (xmlEvent.isEndElement()) {
    EndElement endElement = xmlEvent.asEndElement();
    if (endElement.getName().getLocalPart().equals(&quot;Shoes&quot;)) {
        shoesList.add(shoes);
        shoes = null; // &lt;===== ADD THIS
    }
}

ORIGINAL ANSWER

Your code is:

} else if (startElement.getName().getLocalPart().equals(&quot;title&quot;)){
    xmlEvent = reader.nextEvent();
    shoes.setTitle(xmlEvent.asCharacters().getData());

The problem is that the code isn't checking what type if event follows the START_ELEMENT event. It could be that:

  • Most likely, the element is empty, i.e. &lt;title/&gt; or &lt;title&gt;&lt;title/&gt;, in which case the next event is an END_ELEMENT, and asCharacters() returned null.

  • The element has a comment, e.g. &lt;title&gt;&lt;!-- there is no title --&gt;&lt;title/&gt;, in which case the next event is a COMMENT.

  • The element has mixed content, e.g. &lt;title&gt;foo&lt;![CDATA[bar]]&gt;&lt;title/&gt;, in which case the next event is not the full text.

Retrieving the text content of an element is such a common thing that they added a helper method for that: getElementText():

> Reads the content of a text-only element. Precondition: the current event is START_ELEMENT. Postcondition: The current event is the corresponding END_ELEMENT.
>
> Throws:
> XMLStreamException - if the current event is not a START_ELEMENT or if a non text element is encountered

Which means that your code should be:

} else if (startElement.getName().getLocalPart().equals(&quot;title&quot;)) {
    shoes.setTitle(reader.getElementText());

huangapple
  • 本文由 发表于 2020年10月12日 06:28:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/64309600.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定