背景:
使用mvn org.cyclonedx:cyclonedx-maven-plugin:makeBom命令,在代码各个module的target下生成了bom.xml和bom.json。可以用来统计项目使用了那些组件。之前讲过统计bom.json。这此讲讲统计bom.xml我遇到的大坑。
先根据xml文件定义实体类,使用JAXB将实体类与xml进行匹配,使用注解 @XmlRootElement(name = “AA”)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlAttribute(name = “BB”)
@XmlElement(name = “CC”)
@XmlElementWrapper(name = “DDD”)
所有注解使用方法,自行百度,此处不再赘述。
我遇到的问题:
bom.xml的根节点如下
<bom serialNumber="urn:uuid:dddd3333333333" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
... ...
</bom>
- @XmlElement和@XmlValue不能一起使用
- 没使用@XmlAccessorType(XmlAccessType.FIELD)时候,存在层级关系的属性,会报错存在两个同名标签对象。
- 一直报错:unexpected element (uri:“http://cyclonedx.org/schema/bom/1.4”, local:“bom”). Expected elements are <{}bom>
第三个问题困扰了我好久,
解决1:按照网上写法,在根节点使用@XmlRootElement(name = “AA”,namespace=“http://cyclonedx.org/schema/bom/1.4”),虽然不报错了,因为bom.xml的层级很复杂,出现根节点内的对象节点全部返回null。
解决2:尝试将根bom清理为最干净,简单的xml。并删掉上面的namespace=“http://cyclonedx.org/schema/bom/1.4”,然后将bom的属性标签逐步恢复。
终于发现,删掉命名空间xmlns=“http://cyclonedx.org/schema/bom/1.4”,就能解决问题。那么,代码中如何在读取bom.xml的是,忽略命名空间xmlns呢?<bom> ... ... </bom>
上代码
//创建filter,重点似乎uri为“”
public class NamespaceFilter extends XMLFilterImpl {
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
super.startElement("", localName, qName, atts);
}
}
//xml对象转化为实体对象工具类
@SneakyThrows
public static Object convertXmlFileToObject(Class<?> clazz, String xmlPath) {
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = context.createUnmarshaller();
// 创建一个SAXParser,并将自定义的XMLFilter设置给它
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
NamespaceFilter filter = new NamespaceFilter();
filter.setParent(xr);
// 创建一个SAXSource,并将XMLReader设置为过滤器
InputSource inputSource = new InputSource(new FileInputStream(xmlPath));
SAXSource saxSource = new SAXSource(filter, inputSource);
// 使用SAXSource和Unmarshaller将XML转换为Java对象
Object xmlObject = unmarshaller.unmarshal(saxSource);
// File xmlFile = new File(xmlPath);
// Object xmlObject = unmarshaller.unmarshal(xmlFile);
return xmlObject;
}