1. 程式人生 > >xml去掉schema中沒定義的標籤

xml去掉schema中沒定義的標籤

甲方突然提出這麼個神奇的需求,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;
    }

}