xml去掉schema中沒定義的標籤
阿新 • • 發佈:2019-02-09
甲方突然提出這麼個神奇的需求,schema是定好了的,但是還想在xml中加入一些schema中沒有的標籤。所以為了通過schema校驗,需要在測試前先把schema中沒有的標籤給刪了。
可能我搜索技能不夠強,沒找到現成的方法,只好自己寫了段很智障的程式碼,用了無數個遞迴我都看不下去了。
(所以並沒有什麼參考價值)
測了幾個檔案目前都是正確的,姑且先發一下,萬一哪天手滑把原始碼刪了還能在這找到。
需要兩個jar,dom4j和jaxen,第二個是根據xpath刪除節點的時候用到。
package meiko.schema;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
/**
*
* @author Uebara
* @category 功能:去掉自定義標籤。
*/
public class MyValidateXml {
/**
* index : 用於解析schema,判斷節點在schema當前遍歷節點中的級別。
*/
private int index = 0;
/**
* globalIndex : 索引,當前節點是存入到list中的第幾個節點。
*/
private int globalIndex = 0;
/**
* xmlXpathList : 存放XML檔案所有節點的XPATH。
*/
private ArrayList<String> xmlXpathList = new ArrayList<String>();
/**
* indexList : 存放index的List。
*/
private ArrayList<Integer> indexList = new ArrayList<Integer>();
/**
* schemaNodeList : 存放schema各節點資訊的List。
*/
private ArrayList<SchemaNode> schemaNodeList = new ArrayList<SchemaNode>();
/**
* customList : 存放不存在的父子節點,可外部呼叫,用於列印等功能。
*/
public static ArrayList<String> customList = new ArrayList<String>();
/**
* 對外開放呼叫的函式。 完成XML解析、schema解析、判斷自定義標籤、刪除標籤並生成新檔案的功能。
*
* @param xmlFileName
* @param xsdFileName
* @return newXmlFileName
*/
public String GetXmlWithoutCustomLabel(String xmlFileName, String xsdFileName) {
try {
getXmlNodes(xmlFileName);
getXsdNodes(xsdFileName);
ArrayList<String> deleteList = findCustomLabelInXml();
String newFileName = DeleteNodeByXpath(xmlFileName, deleteList);
return newFileName;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 輸入待處理的XML檔案路徑、需要刪除的XPATH List。 刪除XML中的指定節點並生成新XML檔案,返回新檔案的名稱。
*
* @param xmlFileName
* @param deleteList
* @return outputFileName
* @throws Exception
*/
private String DeleteNodeByXpath(String xmlFileName, ArrayList<String> deleteList) throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new File(xmlFileName));
Element root = document.getRootElement();
for (String deleteContent : deleteList) {
Node node = root.selectSingleNode(deleteContent);
if (node != null) {
node.getParent().setText("");// 如果不setText為空,則在刪除節點的地方會留下空格,也許會引起其他錯誤。
node.getParent().remove(node);// 先node.getParent()再remove才能成功刪除。
}
}
String outputFile = xmlFileName.substring(0, xmlFileName.lastIndexOf(".")) + "_刪除自定義標籤.xml";
FileOutputStream writerStream = new FileOutputStream(outputFile);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(writerStream, "UTF-8"));
writer.write(document.asXML());
writer.close();
return outputFile;
}
/**
* 獲得XML檔案所有節點的XPATH。 呼叫ExtraChilds函式。
*
* @param xmlFileName
*/
private void getXmlNodes(String xmlFileName) {
try {
SAXReader reader = new SAXReader();
Document document;
document = reader.read(new File(xmlFileName));
Element root = document.getRootElement();
ExtraChilds(root);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 從根節點開始遞迴,將所有XPATH存入xmlXpathList。
*
* @param node
*/
@SuppressWarnings("unchecked")
private void ExtraChilds(Element node) {
xmlXpathList.add(node.getPath());
// 進行子節點遍歷
List<Element> childNodes = node.elements();
for (Element childNode : childNodes) {
ExtraChilds(childNode);
}
}
/**
* 獲得schema檔案的所有節點。 呼叫ExtractSchemaNodes函式。
*
* @param xsdFileName
*/
private void getXsdNodes(String xsdFileName) {
try {
SAXReader reader = new SAXReader();
Document document = reader.read(new File(xsdFileName));
Element root = document.getRootElement();
ExtractSchemaNodes(root);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 從根節點開始遞迴,將所有節點資訊存入schemaNodeList。 只考慮兩個節點間的父子關係。
*
* @param node
*/
@SuppressWarnings("unchecked")
private void ExtractSchemaNodes(Element node) {
// typeName : 節點的type屬性; nodeName : 節點的名稱;
// nodeType : 節點的型別(name\ref\type三種);
String typeName = "", nodeName = "", nodeType = "";
boolean isHaveValue = false;
if (node.attributeValue("name") != null && node.getName() == "element") {
// 只有element:name型別的節點才可能有type(吧)
if (node.attributeValue("type") != null)
typeName = node.attributeValue("type");
nodeType = "name";
nodeName = node.attributeValue("name");
isHaveValue = true;
} else if (node.attributeValue("ref") != null && node.getName() == "element") {
nodeType = "ref";
nodeName = node.attributeValue("ref");
isHaveValue = true;
} else if (node.attributeValue("name") != null && node.getName() == "complexType") {
nodeType = "type";
nodeName = node.attributeValue("name");
isHaveValue = true;
}
if (isHaveValue) {
SchemaNode schemaNode = new SchemaNode();
int tempglobalIndex = globalIndex;
String parentName = "/";
indexList.add(index);
// 如果當前節點的index不為1,且與上一個節點的差值為1,說明與上一個節點中間有choice等內容,且應與上一個節點是平級關係。
// 因此將當前節點的index設定為與上一個節點的index相同
if (indexList.get(tempglobalIndex) != 1
&& indexList.get(tempglobalIndex) - indexList.get(tempglobalIndex - 1) == 1) {
indexList.set(tempglobalIndex, indexList.get(tempglobalIndex - 1));
}
if (indexList.get(tempglobalIndex) == 1) {
// 如果當前節點的index為1,說明當前節點沒有父節點,可能有子節點。
} else if (indexList.get(tempglobalIndex) > indexList.get(tempglobalIndex - 1)) {
// 如果當前節點的index大於上一個節點,說明上一節點是當前節點的父節點。
parentName = schemaNodeList.get(tempglobalIndex - 1).getNodeName();
} else if (indexList.get(tempglobalIndex) <= indexList.get(tempglobalIndex - 1)) {
// 如果當前節點的index小於上一個節點,往前尋找比當前節點index小的節點,即當前節點的父節點。
int preSearchIndex = tempglobalIndex;
while (indexList.get(preSearchIndex) <= indexList.get(tempglobalIndex - 1)
&& tempglobalIndex - 1 >= 0) {
tempglobalIndex--;
}
parentName = schemaNodeList.get(tempglobalIndex - 1).getNodeName();
}
schemaNode.setType(nodeType);
schemaNode.setNodeName("/" + nodeName);
schemaNode.setParentName(parentName);
schemaNode.setAttributeType(typeName);
schemaNodeList.add(schemaNode);
globalIndex++;
}
List<Element> childNodes = node.elements();
for (Element childNode : childNodes) {
// 每進入一次遞迴,index++,從遞迴出來,index--。以此判斷當前節點屬於第幾級。
index++;
ExtractSchemaNodes(childNode);
index--;
}
}
/**
* 找到xml檔案中的自定義標籤,即schema中沒有定義的標籤。
*
* @return
*/
private ArrayList<String> findCustomLabelInXml() {
// TODO Auto-generated method stub
ArrayList<String> deleteList = new ArrayList<String>();
for (String oneXpath : xmlXpathList) {
boolean isDeleted = false;
// 將XPATH拆為節點名稱的陣列。2個為一組,判斷在schema中是否有上下級關係。
String[] xpathArr = oneXpath.split("/");
for (int i = 0; i < xpathArr.length - 1; i++) {
isDeleted = false;
boolean isFind = false;
// 直接找到
for (SchemaNode schemaNode : schemaNodeList) {
if (schemaNode.getParentName().equals("/" + xpathArr[i])
&& schemaNode.getNodeName().equals("/" + xpathArr[i + 1])) {
isFind = true;
break;
}
}
// 如果不能直接找到子標籤,可能是使用了type,在type中尋找子標籤
if (!isFind) {
for (SchemaNode schemaNode : schemaNodeList) {
// 尋找與父標籤名稱相同的NodeName,如果找到的標籤有type屬性,進入下一輪迴圈。
if (schemaNode.getNodeName().equals("/" + xpathArr[i])
&& !schemaNode.getAttributeType().equals("")) {
for (SchemaNode findAttribute : schemaNodeList) {
// 尋找與父標籤的type屬性名稱一樣的NodeName,如果找到了,進入下一輪迴圈。
if (findAttribute.getNodeName().substring(1).equals(schemaNode.getAttributeType())) {
for (SchemaNode findTypeNode : schemaNodeList) {
// 尋找與type屬性同名的NodeName的子標籤中是否有待查詢的子標籤名稱。
if (findTypeNode.getParentName().equals(findAttribute.getNodeName())
&& findTypeNode.getNodeName().equals("/" + xpathArr[i + 1])) {
isFind = true;
break;
}
}
break;
}
}
break;
}
}
}
if (!isFind) {
isDeleted = true;
customList.add(xpathArr[i]+"沒有子節點"+xpathArr[i+1]);
}
}
// 如果迴圈結束,當前XPATH中有任何一組沒找到父子關係,則需要刪除。
if (isDeleted)
deleteList.add(oneXpath);
}
return deleteList;
}
// public static void main(String[] args) throws Exception {
// MyValidateXml m = new MyValidateXml();
// String xmlFileName = "thisMain.xml";
// String xsdFileName = "thisSchema.xsd";
//
// m.GetXmlWithoutCustomLabel(xmlFileName, xsdFileName);
// }
}
用到的自定義類SchemaNode.java
package meiko.schema;
import java.util.ArrayList;
public class SchemaNode {
private String Type;
private String NodeName;
private String ParentName;
private String AttributeType;
/**
* 初始化,全為空
*/
public SchemaNode(){
Type = "";
NodeName = "";
ParentName = "";
AttributeType = "";
}
public String getType() {
return Type;
}
public void setType(String type) {
Type = type;
}
public String getNodeName() {
return NodeName;
}
public void setNodeName(String nodeName) {
NodeName = nodeName;
}
public String getParentName() {
return ParentName;
}
public void setParentName(String parentName) {
ParentName = parentName;
}
public String getAttributeType() {
return AttributeType;
}
public void setAttributeType(String attributeType) {
AttributeType = attributeType;
}
}