XML 发票解析

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 {
    @Autowired
    InvoiceService 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 {
    @Override
    public Invoice parseOfdFile(MultipartFile file) {
        Invoice invoice = XmlUtils.parseXmlFile(file);
        return invoice;
    }
}

4. 结果展示

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

### 处理记账凭证 XML 发票的方法 #### 解析XML发票结构 为了有效处理与记账凭证相关的XML发票,理解其内部结构至关重要。通常情况下,XML文档遵循特定模式定义(Schema Definition),这有助于解析器准确读取所需的数据字段。对于数电发票而言,这类文件会按照财政部规定标准构建[^1]。 ```python import xml.etree.ElementTree as ET def parse_invoice_xml(file_path): tree = ET.parse(file_path) root = tree.getroot() invoice_data = {} for child in root: tag = child.tag.split('}')[1] if '}' in child.tag else child.tag text = child.text.strip() if child.text is not None else '' invoice_data[tag] = text return invoice_data ``` 此代码片段展示了如何利用Python内置库`xml.etree.ElementTree`来加载并遍历一个XML文件的内容,提取其中的关键信息到字典对象中以便后续操作。 #### 验证XML发票的有效性 确保接收到的XML发票符合预期格式非常重要。可以采用预设好的XSD (XML Schema Definition) 文件来进行验证工作。这种方式能够帮助确认每一份传入的XML是否满足既定的标准要求。 ```python from lxml import etree def validate_invoice_schema(xml_file, xsd_file): with open(xsd_file, 'r') as schema_file: schema_doc = etree.parse(schema_file) schema = etree.XMLSchema(schema_doc) doc = etree.parse(xml_file) result = schema.validate(doc) return result ``` 上述函数接收两个参数:一个是待检验的XML文件路径,另一个则是用于校验该XML合法性的XSD模板位置。通过调用`etree.XMLSchema()`方法创建了一个基于给定XSD的新实例,并最终返回布尔值表示验证的结果。 #### 将XML转换成其他格式 考虑到实际应用场景的需求多样性,在某些时候可能还需要把原始的XML形式转化为更易于展示的形式如PDF或OFD等。这一过程涉及到渲染引擎的选择以及具体实现逻辑的设计。 ```bash # 假设已经安装了必要的工具链比如wkhtmltopdf或其他适合于目标平台的技术栈 $ wkhtmltopdf input.xml output.pdf ``` 命令行示例说明了当具备适当环境配置时可以直接运用第三方软件完成从HTML/XML至PDF之间的转变。当然也可以考虑集成相应的API服务接口以简化流程管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值