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

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

Why I get NullPointerException when running StAX Parser?

问题

  1. 我试图在Java中编写一个StAX XML解析器但总是遇到NullPointerException错误请帮我解决这个问题完整的问题
  2. > Exception in thread "main" java.lang.NullPointerException
  3. > at org.example.shoesshop.parser.STAXParser.parseXMLfile(STAXParser.java:68)
  4. > at org.example.shoesshop.parser.STAXParser.main(STAXParser.java:101)
  5. 这是一个用于StAX解析器的类
  6. public class STAXParser extends DefaultHandler {
  7. private static List<Shoes> parseXMLfile(String fileName) {
  8. // ...
  9. //(原始代码)
  10. // ...
  11. }
  12. public static void main(String[] args) throws Exception {
  13. // ...
  14. //(原始代码)
  15. // ...
  16. }
  17. }
  18. 这是一个XML文件的示例
  19. <?xml version="1.0" encoding="UTF-8"?>
  20. <!---->
  21. </ss:ShoesShop>
  22. 这是一个用于鞋子的Java
  23. @XmlAccessorType(XmlAccessType.FIELD)
  24. @XmlType(name = "Shoes", propOrder = {
  25. "title",
  26. "brand",
  27. //(略)
  28. })
  29. public class Shoes extends Entity {
  30. // ...
  31. //(原始代码)
  32. // ...
  33. }
  34. 我还需要知道如何将接收到的数据写入新的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:

  1. public class STAXParser extends DefaultHandler {
  2. private static List&lt;Shoes&gt; parseXMLfile(String fileName){
  3. List&lt;Shoes&gt; shoesList = new ArrayList&lt;&gt;();
  4. Shoes shoes = null;
  5. XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
  6. try {
  7. XMLEventReader reader = xmlInputFactory.createXMLEventReader(new FileInputStream(fileName));
  8. while (reader.hasNext()){
  9. XMLEvent xmlEvent = reader.nextEvent();
  10. if(xmlEvent.isStartElement()){
  11. StartElement startElement = xmlEvent.asStartElement();
  12. if(startElement.getName().getLocalPart().equals(&quot;Shoes&quot;)){
  13. shoes = new Shoes();
  14. Attribute idAttr = startElement.getAttributeByName(new QName(&quot;id&quot;));
  15. if(idAttr != null){
  16. shoes.setId(Integer.parseInt(idAttr.getValue()));
  17. }
  18. } else if (startElement.getName().getLocalPart().equals(&quot;title&quot;)){
  19. xmlEvent = reader.nextEvent();
  20. shoes.setTitle(xmlEvent.asCharacters().getData()); // error line 68
  21. } else if (startElement.getName().getLocalPart().equals(&quot;brand&quot;)){
  22. xmlEvent = reader.nextEvent();
  23. shoes.setBrand(Brand.fromValue(xmlEvent.asCharacters().getData()));
  24. } else if (startElement.getName().getLocalPart().equals(&quot;category&quot;)){
  25. xmlEvent = reader.nextEvent();
  26. shoes.setCategory(Category.fromValue(xmlEvent.asCharacters().getData()));
  27. } else if (startElement.getName().getLocalPart().equals(&quot;season&quot;)){
  28. xmlEvent = reader.nextEvent();
  29. shoes.setSeason(Season.fromValue(xmlEvent.asCharacters().getData()));
  30. } else if (startElement.getName().getLocalPart().equals(&quot;price&quot;)){
  31. xmlEvent = reader.nextEvent();
  32. shoes.setPrice(Double.parseDouble(xmlEvent.asCharacters().getData()));
  33. }
  34. }
  35. if(xmlEvent.isEndElement()){
  36. EndElement endElement = xmlEvent.asEndElement();
  37. if(endElement.getName().getLocalPart().equals(&quot;Shoes&quot;)){
  38. shoesList.add(shoes);
  39. }
  40. }
  41. }
  42. } catch (FileNotFoundException | XMLStreamException exc) {
  43. exc.printStackTrace();
  44. } return shoesList;
  45. }
  46. public static void main(String[] args) throws Exception {
  47. System.out.println(&quot;STAX Parser&quot;);
  48. System.out.println();
  49. System.out.println(&quot;Result: \n&quot;);
  50. System.out.println();
  51. String fileName = &quot;ShoesShop.xml&quot;;
  52. List&lt;Shoes&gt; shoesList = parseXMLfile(fileName); //error line 101
  53. for (Shoes shoes:shoesList){
  54. System.out.println(shoes.toString());
  55. }
  56. }
  57. }

Here's an XML-file

  1. &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
  2. &lt;?xml-stylesheet type = &quot;text/xsl&quot; href = &quot;ShoesShop.xsl&quot;?&gt;
  3. &lt;ss:ShoesShop xmlns:ss=&quot;http://www.example.org/ShoesShop&quot;
  4. xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
  5. xsi:schemaLocation=&quot;http://www.example.org/ShoesShop ShoesShop.xsd &quot;&gt;
  6. &lt;ss:shoes id=&quot;1&quot; stock=&quot;true&quot;&gt;
  7. &lt;ss:title&gt;Baltrum&lt;/ss:title&gt;
  8. &lt;ss:brand&gt;Gucci&lt;/ss:brand&gt;
  9. &lt;ss:category&gt;Boots&lt;/ss:category&gt;
  10. &lt;ss:season&gt;fall&lt;/ss:season&gt;
  11. &lt;ss:gender&gt;
  12. &lt;ss:male&gt;male&lt;/ss:male&gt;
  13. &lt;/ss:gender&gt;
  14. &lt;ss:details&gt;
  15. &lt;ss:highlights&gt;Highlights text 1&lt;/ss:highlights&gt;
  16. &lt;ss:composition&gt;Composition text 1&lt;/ss:composition&gt;
  17. &lt;/ss:details&gt;
  18. &lt;ss:price&gt;734.0&lt;/ss:price&gt;
  19. &lt;/ss:shoes&gt;
  20. &lt;ss:shoes id=&quot;2&quot; stock=&quot;true&quot; mostWanted = &quot;true&quot;&gt;
  21. &lt;ss:title&gt;Amalfi&lt;/ss:title&gt;
  22. &lt;ss:brand&gt;Dior&lt;/ss:brand&gt;
  23. &lt;ss:category&gt;Mules&lt;/ss:category&gt;
  24. &lt;ss:season&gt;winter&lt;/ss:season&gt;
  25. &lt;ss:gender&gt;
  26. &lt;ss:female&gt;female&lt;/ss:female&gt;
  27. &lt;/ss:gender&gt;
  28. &lt;ss:details&gt;
  29. &lt;ss:highlights&gt;Highlights text 2&lt;/ss:highlights&gt;
  30. &lt;ss:composition&gt;Composition text 2&lt;/ss:composition&gt;
  31. &lt;/ss:details&gt;
  32. &lt;ss:price&gt;364.0&lt;/ss:price&gt;
  33. &lt;/ss:shoes&gt;
  34. &lt;ss:shoes id=&quot;3&quot; stock=&quot;true&quot; mostWanted = &quot;true&quot;&gt;
  35. &lt;ss:title&gt;Korfu&lt;/ss:title&gt;
  36. &lt;ss:brand&gt;Mary Katrantzou&lt;/ss:brand&gt;
  37. &lt;ss:category&gt;Sneakers&lt;/ss:category&gt;
  38. &lt;ss:season&gt;spring&lt;/ss:season&gt;
  39. &lt;ss:gender&gt;
  40. &lt;ss:female&gt;female&lt;/ss:female&gt;
  41. &lt;/ss:gender&gt;
  42. &lt;ss:details&gt;
  43. &lt;ss:highlights&gt;Highlights text 3&lt;/ss:highlights&gt;
  44. &lt;ss:composition&gt;Composition text 3&lt;/ss:composition&gt;
  45. &lt;/ss:details&gt;
  46. &lt;ss:price&gt;173.0&lt;/ss:price&gt;
  47. &lt;/ss:shoes&gt;
  48. &lt;/ss:ShoesShop&gt;

Also here's a Java class for Shoes

  1. @XmlAccessorType(XmlAccessType.FIELD)
  2. @XmlType(name = &quot;Shoes&quot;, propOrder = {
  3. &quot;title&quot;,
  4. &quot;brand&quot;,
  5. &quot;category&quot;,
  6. &quot;season&quot;,
  7. &quot;gender&quot;,
  8. &quot;details&quot;,
  9. &quot;price&quot;
  10. })
  11. public class Shoes
  12. extends Entity
  13. {
  14. @XmlElement(required = true)
  15. protected String title;
  16. @XmlElement(required = true)
  17. @XmlSchemaType(name = &quot;string&quot;)
  18. protected Brand brand;
  19. @XmlElement(required = true)
  20. @XmlSchemaType(name = &quot;string&quot;)
  21. protected Category category;
  22. @XmlElement(required = true)
  23. @XmlSchemaType(name = &quot;string&quot;)
  24. protected Season season;
  25. @XmlElement(required = true)
  26. protected Shoes.Gender gender;
  27. @XmlElement(required = true)
  28. protected Shoes.Details details;
  29. protected double price;
  30. @XmlAttribute(name = &quot;stock&quot;, required = true)
  31. protected boolean stock;
  32. @XmlAttribute(name = &quot;mostWanted&quot;)
  33. protected Boolean mostWanted;
  34. public String getTitle() {
  35. return title;
  36. }
  37. public void setTitle(String value) {
  38. this.title = value;
  39. }
  40. public Brand getBrand(){
  41. return brand;
  42. }
  43. public void setBrand(Brand value){
  44. this.brand = value;
  45. }
  46. public Category getCategory(){
  47. return category;
  48. }
  49. public void setCategory(Category value){
  50. this.category = value;
  51. }
  52. public Season getSeason(){
  53. return season;
  54. }
  55. public void setSeason(Season value) {
  56. this.season = value;
  57. }
  58. public Shoes.Gender getGender() {
  59. return gender;
  60. }
  61. public void setGender(Shoes.Gender value) {
  62. this.gender = value;
  63. }
  64. public Shoes.Details getDetails() {
  65. return details;
  66. }
  67. public void setDetails(Shoes.Details value) {
  68. this.details = value;
  69. }
  70. public double getPrice() {
  71. return price;
  72. }
  73. public void setPrice(double value) {
  74. this.price = value;
  75. }
  76. public boolean isStock() {
  77. return stock;
  78. }
  79. public void setStock(boolean value) {
  80. this.stock = value;
  81. }
  82. public Boolean isMostWanted() {
  83. return mostWanted;
  84. }
  85. public void setMostWanted(Boolean value) {
  86. this.mostWanted = value;
  87. }
  88. @XmlAccessorType(XmlAccessType.FIELD)
  89. @XmlType(name = &quot;&quot;, propOrder = {
  90. })
  91. public static class Details {
  92. @XmlElement(required = true)
  93. protected String highlights;
  94. @XmlElement(required = true)
  95. protected String composition;
  96. public String getHighlights() {
  97. return highlights;
  98. }
  99. public void setHighlights(String value) {
  100. this.highlights = value;
  101. }
  102. public String getComposition() {
  103. return composition;
  104. }
  105. public void setComposition(String value) {
  106. this.composition = value;
  107. }
  108. }
  109. @XmlAccessorType(XmlAccessType.FIELD)
  110. @XmlType(name = &quot;&quot;, propOrder = {
  111. &quot;\u043c\u0443\u0436\u0441\u043a\u043e\u0439Or\u0416\u0435\u043d\u0441\u043a\u0438\u0439&quot;
  112. })
  113. public static class Gender {
  114. @XmlElementRefs({
  115. @XmlElementRef(name = &quot;\u0436\u0435\u043d\u0441\u043a\u0438\u0439&quot;, namespace = &quot;http://www.example.org/ShoesShop&quot;, type = JAXBElement.class, required = false),
  116. @XmlElementRef(name = &quot;\u043c\u0443\u0436\u0441\u043a\u043e\u0439&quot;, namespace = &quot;http://www.example.org/ShoesShop&quot;, type = JAXBElement.class, required = false)
  117. })
  118. protected List&lt;JAXBElement&lt;String&gt;&gt; maleOrFemale;
  119. public List&lt;JAXBElement&lt;String&gt;&gt; getMaleOrFemale() {
  120. if (maleOrFemale == null) {
  121. maleOrFemale = new ArrayList&lt;JAXBElement&lt;String&gt;&gt;();
  122. }
  123. return this.maleOrFemale;
  124. }
  125. }
  126. @Override
  127. public String toString(){
  128. StringBuilder builder = new StringBuilder();
  129. builder.append(&quot;[title=&quot;);
  130. builder.append(title);
  131. builder.append(&quot;, brand=&quot;);
  132. builder.append(brand);
  133. builder.append(&quot;, category=&quot;);
  134. builder.append(category);
  135. builder.append(&quot;, season=&quot;);
  136. builder.append(season);
  137. builder.append(&quot;, price=&quot;);
  138. builder.append(price);
  139. builder.append(&quot;]&quot;);
  140. return builder.toString();
  141. }
  142. }

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

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

原始回答

您的代码是:

  1. } else if (startElement.getName().getLocalPart().equals("title")){
  2. xmlEvent = reader.nextEvent();
  3. 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,或者如果遇到非文本元素

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

  1. } else if (startElement.getName().getLocalPart().equals("title")) {
  2. 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:

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

ORIGINAL ANSWER

Your code is:

  1. } else if (startElement.getName().getLocalPart().equals(&quot;title&quot;)){
  2. xmlEvent = reader.nextEvent();
  3. 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:

  1. } else if (startElement.getName().getLocalPart().equals(&quot;title&quot;)) {
  2. 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:

确定