主要是搜集各个标签出现的案例(主要记录孩子特征,属性特征),最终根据每个案例,综合得出标签特性,最终拼接字符串
实际,IDEA会根据已经存在的推断提示,若有一个较好的案例,可以直接把示例复制到xml文件使用提示编写完毕再删除
使用效果
随便找的原始xml文件
生成效果
使用
全部代码
/**
* @author 邵康
* @date 2021/8/11 14:27
*/
public class DtdCreator {
@SneakyThrows//直接输出的重载
public void create(InputStream in) {
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
create(in, out);
String msg = out.toString("UTF-8");
System.out.println(msg);
}
// 保存到 指定流的重载
public void create(InputStream in, OutputStream out) {
Element element = createElement(in);
handleElement(element, element.getTagName());
handleTags(out);
}
@SneakyThrows//处理标签写入流
private void handleTags(OutputStream out) {
for (String key : nodeMap.keySet()) {
List<Tag> tags = nodeMap.get(key);
String content = handleTag(key, tags);
out.write(content.getBytes());
}
}
// 构建 标签 返回有关该标签的字符串
private String handleTag(String key, List<Tag> tags) {
List<String> sonTags = parseSonTags(tags);
Map<String, String> attrs = parseAttrs(tags);
StringBuilder builder=new StringBuilder();
buildTag(builder,key,sonTags);
buildAttrs(builder,key,attrs);
return builder.toString();
}
// 构建属性
private void buildAttrs(StringBuilder builder, String key, Map<String, String> attrs) {
for (String attr:attrs.keySet()){
builder.append("<!ATTLIST ").append(key).append(" ").append(attr).append(" #")
.append(attrs.get(attr)).append(" >\n");
}
}
// 构建节点
private void buildTag(StringBuilder builder, String key, List<String> sonTags) {
builder.append("<!ELEMENT ").append(key).append(" (");
if(sonTags.isEmpty()){
builder.append("#PCDATA");
}else {
for (String sonTag:sonTags){
builder.append(sonTag).append(",");
}
builder.setLength(builder.length()-1);
}
builder.append(")>\n");
}
//搜集每个案例孩子 出现的情况
private List<String> parseSonTags(List<Tag> tags) {
//TODO ORDER
Map<String, Set<Integer>> map = new LinkedHashMap<>();
for (Tag tag : tags) {
List<String> names = tag.getTagNames();
int count = 0;
String last = "";
for (String name : names) {
if (name.equals(last)) {
count++;
} else {
addCount(map, count, last);
count = 1;
last = name;
}
}
addCount(map, count, last);
}
List<String> res=new ArrayList<>();
for (String key:map.keySet()){
res.add(parseCount(key,map.get(key),tags.size()));
}
return res;
}
// 根据每个案例孩子出现的情况 判断 子标签次数属性
private String parseCount(String key, Set<Integer> counts, int sum) {
if(counts.size()==sum){ // + or 一个
for (Integer count:counts){
if(count>1)return key+"+";
}
return key;
}else { // ? or *
for (Integer count:counts){
if(count>1)return key+"*";
}
return key+"?";
}
}
// 添加数量
private void addCount(Map<String, Set<Integer>> map, int count, String last) {
if (count == 0) return;
if (!map.containsKey(last)) {
map.put(last, new HashSet<>());
}
map.get(last).add(count);
}
// 直接判断 是否每个案例 都要该属性判断是否必须
private Map<String, String> parseAttrs(List<Tag> tags) {
Map<String, Integer> count = new LinkedHashMap<>();
for (Tag tag : tags) {
for (String attr : tag.getAttrs()) {
count.put(attr, count.getOrDefault(attr, 0) + 1);
}
}
Map<String, String> res = new LinkedHashMap<>();
int num = tags.size();
for (String key : count.keySet()) {
res.put(key, count.get(key) == num ? "REQUIRED" : "IMPLIED");
}
return res;
}
@SneakyThrows// 根据流构建根对象
private Element createElement(InputStream in) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(in);
return document.getDocumentElement();
}
private Map<String, List<Tag>> nodeMap;
public DtdCreator() {
nodeMap = new LinkedHashMap<>();
}
// 递归处理元素
private void handleElement(Element element, String tagName) {
Tag current = new Tag(tagName);
if (!nodeMap.containsKey(tagName)) nodeMap.put(tagName, new ArrayList<>());
nodeMap.get(tagName).add(current);
handleElementAttrs(current, element);
handleElements(current, element);
}
// 处理子元素
private void handleElements(Tag current, Element element) {
NodeList nodes = element.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node item = nodes.item(i);
if (item instanceof Element) {
Element son = (Element) item;
String tagName = son.getTagName();
current.addNodeName(tagName);
handleElement(son, tagName);
}
}
}
// 处理标签属性
private void handleElementAttrs(Tag current, Element element) {
NamedNodeMap map = element.getAttributes();
for (int i = 0; i < map.getLength(); i++) {
Attr item = (Attr) map.item(i);
current.addAttr(item.getName());
}
}
@Data//信息载体
static class Tag {
private String name;
private List<String> tagNames;
private Set<String> attrs;
public Tag(String name) {
this.name = name;
tagNames = new ArrayList<>();
attrs = new HashSet<>();
}
public void addNodeName(String nodeName) {
tagNames.add(nodeName);
}
public void addAttr(String attrName) {
attrs.add(attrName);
}
}
}