XML 发票解析

server/2024/10/19 2:25:53/

文章目录

  • 1. xml 类型发票格式
  • 2. 数据提取思路
    • 2.1 项目结构
  • 3. 提取实现
    • 3.1 实体类
    • 3.2 提取工具类
    • 3.3 controller
    • 3.4 service
  • 4. 结果展示

1. xml 类型发票格式

本文解析的xml类型的发票格式如下
在这里插入图片描述

2. 数据提取思路

通过遍历xml文件中的标签去获得标签对应的文本

2.1 项目结构

在这里插入图片描述

3. 提取实现

3.1 实体类

Invoice

package com.example.xml.entity;import lombok.Data;import java.util.Date;@Data
public class Invoice {private String invoiceNumber; // 发票号码private Date invoiceDate; // 开票日期private String totalAmount;// 总开票金额private String invoiceRemarks;// 发票备注
}

3.2 提取工具类

package com.example.xml.utils;import com.example.xml.entity.Invoice;
import org.dom4j.io.SAXReader;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.springframework.web.multipart.MultipartFile;public class XmlUtils {/*** 调用该方法将前端接受到的文件暂存** @param file*/public static Invoice parseXmlFile(MultipartFile file) {Invoice invoice = new Invoice();File tempFilePath=null;try {// 创建一个临时文件Path tempFile = null;tempFile = Files.createTempFile("tempPrefix", ".xml");tempFilePath = tempFile.toFile();// 将MultipartFile的内容写入到临时文件try (FileOutputStream fos = new FileOutputStream(tempFilePath)) {fos.write(file.getBytes());}// 使用临时文件的路径来调用你的解析方法invoice = extract(tempFilePath);// 删除临时文件,或者在某些情况下保留它
//            tempFilePath.delete();} catch (Exception e) {// 处理异常e.printStackTrace();}finally {// 无论是否发生异常,都尝试删除临时文件if (tempFilePath != null && !tempFilePath.delete()) {// 记录删除失败的情况System.err.println("无法删除临时文件: " + tempFilePath.getAbsolutePath());}}// 返回值return invoice;}/*** 从一个ZIP 文件中提取特定格式的发票信息,并构建一个 Invoice 对象来存储这些信息** @param file* @return* @throws IOException* @throws DocumentException*/public static Invoice extract(File file) throws DocumentException, ParseException {Invoice invoice = new Invoice();//创建发票实例SAXReader reader = new SAXReader();Document document = reader.read(file);// 读取XML文件// 获取备注中的部分信息Element root = document.getRootElement(); // <EInvoice>Element eInvoiceData = root.element("EInvoiceData"); // <EInvoiceData>// 备注中的销方信息提取Element sellerInformation = eInvoiceData.element("SellerInformation"); // <SellerInformation>Element sellerBankName = sellerInformation.element("SellerBankName");Element sellerBankAccNum = sellerInformation.element("SellerBankAccNum");String sellerBankNameValue="";String sellerBankAccNumValue="";if(sellerBankName!=null){sellerBankNameValue = sellerBankName.getTextTrim();//获取<SellerBankName>的文本内容【销方开户银行】}if(sellerBankAccNum!=null){sellerBankAccNumValue = sellerBankAccNum.getTextTrim();//获取<SellerBankAccNum>的文本内容【销方银行账号】}// 备注中的购方信息提取Element buyerInformation = eInvoiceData.element("BuyerInformation"); // <BuyerInformation>Element buyerBankName = buyerInformation.element("BuyerBankName");Element buyerBankAccNum = buyerInformation.element("BuyerBankAccNum");String buyerBankNameValue="";String buyerBankAccNumValue="";if(buyerBankName!=null){buyerBankNameValue = buyerBankName.getTextTrim();//获取<BuyerBankName>的文本内容【购方开户银行】}if(buyerBankAccNum!=null){buyerBankAccNumValue = buyerBankAccNum.getTextTrim();//获取<BuyerBankAccNum>的文本内容【购方银行账号】}// 开票金额提取Element issuItemInformation = eInvoiceData.element("IssuItemInformation"); // <IssuItemInformation>Element totalAmount = issuItemInformation.element("TotaltaxIncludedAmount"); // <TotaltaxIncludedAmount>String totalAmountValue="";if(totalAmount!=null){totalAmountValue = totalAmount.getTextTrim();// 获取<TotaltaxIncludedAmount>的文本内容}// 发票号码Element taxSupervisionInfo = root.element("TaxSupervisionInfo"); // <TaxSupervisionInfo>Element invoiceNumber = taxSupervisionInfo.element("InvoiceNumber");String invoiceNumberValue="";if(invoiceNumber!=null){invoiceNumberValue = invoiceNumber.getTextTrim();//获取<InvoiceNumber>的文本内容【发票号码】}//开票日期Element issueTime = taxSupervisionInfo.element("IssueTime");String issueTimeValue="";if(issueTime!=null){issueTimeValue = issueTime.getTextTrim();//获取<IssueTime>的文本内容【开票日期】}//创建Invoice实例,并填充发票信息if (invoiceNumberValue != null && invoiceNumberValue != "") {//发票号码invoice.setInvoiceNumber(invoiceNumberValue);}if (issueTimeValue != null && issueTimeValue != "") {//开票日期SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy-MM-dd");Date parsedDate = inputDateFormat.parse(issueTimeValue);invoice.setInvoiceDate(parsedDate);}if (totalAmountValue != null && totalAmountValue != "") {// 开票金额invoice.setTotalAmount(totalAmountValue);}//在设置之前排好发票备注的版型String note = setNote(buyerBankNameValue, buyerBankAccNumValue, sellerBankNameValue, sellerBankAccNumValue);invoice.setInvoiceRemarks(note);return invoice;}/*** 拼接备注信息** @param buyerBankNameValue    购方开户银行* @param buyerBankAccNumValue  购方银行账号* @param sellerBankNameValue   销方开户银行* @param sellerBankAccNumValue 销方银行账号* @return*/public static String setNote(String buyerBankNameValue, String buyerBankAccNumValue, String sellerBankNameValue, String sellerBankAccNumValue) {String resultNote = "";if (buyerBankNameValue != null && buyerBankNameValue != "") {resultNote += "购方开户银行:" + buyerBankNameValue + ";";}if (buyerBankAccNumValue != null && buyerBankAccNumValue != "") {resultNote += "银行账号:" + buyerBankAccNumValue + ";";}if (sellerBankNameValue != null && sellerBankNameValue != "") {resultNote += "销方开户银行:" + sellerBankNameValue + ";";}if (sellerBankAccNumValue != null && sellerBankAccNumValue != "") {resultNote += "银行账号:" + sellerBankAccNumValue + ";";}return resultNote;}}

3.3 controller

package com.example.xml.controller;import com.example.xml.entity.Invoice;
import com.example.xml.service.InvoiceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;@RestController
@RequestMapping("/invoice")
public class InvoiceController {@AutowiredInvoiceService invoiceService;/*** @param*/@CrossOrigin(origins = "http://localhost:8081", allowedHeaders = "*", allowCredentials = "true")@PostMapping("/upload")public ResponseEntity<Object> uploadFile(@RequestParam("file") MultipartFile file) {try {// 调用你的文件解析服务Invoice parsedData = invoiceService.parseOfdFile(file);// 返回解析后的数据return ResponseEntity.ok(parsedData);} catch (Exception e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error parsing file");}}
}

3.4 service

InvoiceService

package com.example.xml.service;import com.example.xml.entity.Invoice;
import org.springframework.web.multipart.MultipartFile;public interface InvoiceService {Invoice parseOfdFile(MultipartFile file);}

InvoiceServiceImpl

package com.example.xml.service.impl;import com.example.xml.entity.Invoice;
import com.example.xml.service.InvoiceService;
import com.example.xml.utils.XmlUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;@Service
public class InvoiceServiceImpl implements InvoiceService {@Overridepublic Invoice parseOfdFile(MultipartFile file) {Invoice invoice = XmlUtils.parseXmlFile(file);return invoice;}
}

4. 结果展示

postman测试结果如下
在这里插入图片描述


http://www.ppmy.cn/server/96534.html

相关文章

使用GCC编译Notepad++的插件

Notepad的本体1是支持使用MSVC和GCC编译的2&#xff0c;但是Notepad插件的官方文档3里却只给出了MSVC的编译指南4。 网上也没有找到相关的讨论&#xff0c;所以我尝试在 Windows 上使用 MinGW&#xff0c;基于 GCC-8.1.0 的 posix-sjlj 线程版本5&#xff0c;研究一下怎么编译…

canvas-视频绘制

通过Canvas元素来实时绘制一个视频帧&#xff0c;并在视频帧上叠加一个图片的功能可以当作水印。 获取Canvas元素&#xff1a; let canvas document.getElementById(canvas) 通过getElementById函数获取页面中ID为canvas的Canvas元素&#xff0c;并将其存储在变量canvas中。 …

极简聊天室-websocket版(双向通信)

我们知道WebSocket是可以双向通信的&#xff0c;把极简聊天室代码又改了一下&#xff0c;前端发信息到后端也使用websocket&#xff0c;其实代码量更少了。。。 const express require(express); const app express(); var wsServer require(express-ws)(app)var msgs[];ap…

C#初级——字典Dictionary

字典 字典是C#中的一种集合&#xff0c;它存储键值对&#xff0c;并且每个键与一个值相关联。 创建字典 Dictionary<键的类型, 值的类型> 字典名字 new Dictionary<键的类型, 值的类型>(); Dictionary<int, string> dicStudent new Dictionary<int, str…

在Linux中,什么叫做线程

在Linux中&#xff0c;什么叫做线程&#xff1f; CPU调度的基本单位。 在Linux中&#xff0c;什么叫做进程&#xff1f; 内核视角&#xff1a; 承担分配系统资源的基本实体。 一个进程内部可以有多个执行流。 task_struct可以理解为轻量级进程。 线程是进程内部的一个分支…

PHP同城派送系统小程序源码

&#x1f69a;【同城生活新速度】同城派送系统&#xff0c;让每一刻都触手可及&#x1f680; &#x1f3d9;️ 一、即时送达&#xff0c;同城无界 你是否曾经因为急需某样物品却找不到即时送达的服务而焦急万分&#xff1f;现在&#xff0c;同城派送系统来解救你了&#xff0…

Parsing error: The keyword ‘interface‘ is reserved配置优化

当我们在创建Vue项目时,Vue默认是配置了eslint代码规范检查的,不过我们在项目中Typescript来编写代码时,却报了标题的错误,对应的代码如下: <script lang="ts"> export default{name: "DlHeader" } </script><script setup lang=&quo…

rocket 如何解决消息堆积问题、如何消息丢失问题、r安全问题(设置密码)、时间复杂度。

20240803 一、 如何解决消息堆积问题&#xff1f;一般认为单条队列消息差值>10w时 算堆积问题生产太快了线程数量的设置挤压问题 消费者消费出现问题如果堆积的消息不想要了&#xff0c;可以直接跳过堆积 二、 信息丢失问题为什么会丢失解决思路1 记录下来解决思路2 使用roc…