在java中表示XPath列表的最佳方式

时间:2015-08-23 08:03:43

标签: java json xml xpath jstree

我有一个从我希望在Java对象中分层表示的模式生成的XPath列表。基本上我想从XPath中分离每个“/”并将它们视为单个对象,没有重复。目前,我已将列表加载到具有包含子对象的HashMap的对象中。

我想做类似的事情但是使用ArrayList。这是因为我想生成一个没有HashMap键的JSON字符串。该消息将用于显示树视图(使用jstree)。

输入:

Root/Customers/Customer/CompanyName
Root/Customers/Customer/ContactName
Root/Customers/Customer/ContactTitle
Root/Customers/Customer/Phone
Root/Customers/Customer/Fax
Root/Customers/Customer/FullAddress/Address
Root/Customers/Customer/FullAddress/City
Root/Customers/Customer/FullAddress/Region
Root/Customers/Customer/FullAddress/PostalCode
Root/Customers/Customer/FullAddress/Country
Root/Orders/Order/CustomerID
Root/Orders/Order/EmployeeID
Root/Orders/Order/OrderDate
Root/Orders/Order/RequiredDate
Root/Orders/Order/ShipInfo/ShipVia
Root/Orders/Order/ShipInfo/Freight
Root/Orders/Order/ShipInfo/ShipName
Root/Orders/Order/ShipInfo/ShipAddress
Root/Orders/Order/ShipInfo/ShipCity
Root/Orders/Order/ShipInfo/ShipRegion
Root/Orders/Order/ShipInfo/ShipPostalCode
Root/Orders/Order/ShipInfo/ShipCountry

这是我目前的输出:

{
    "text": "Root",
    "children": {
        "Root": {
            "text": "Root",
            "children": {
                "Orders": {
                    "text": "Orders",
                    "children": {
                        "Order": {
                            "text": "Order",
                            "children": {
                                "RequiredDate": {
                                    "text": "RequiredDate"
                                },
                                "ShipInfo": {
                                    "text": "ShipInfo",
                                    "children": {
                                        "ShipName": {
                                            "text": "ShipName"
                                        },
                                        "ShipCity": {
                                            "text": "ShipCity"
                                        },
                                        "ShipAddress": {
                                            "text": "ShipAddress"
                                        },
                                        "ShipVia": {
                                            "text": "ShipVia"
                                        },
                                        "ShipPostalCode": {
                                            "text": "ShipPostalCode"
                                        },
                                        "ShipCountry": {
                                            "text": "ShipCountry"
                                        },
                                        "Freight": {
                                            "text": "Freight"
                                        },
                                        "ShipRegion": {
                                            "text": "ShipRegion"
                                        }
                                    }
                                },
                                "CustomerID": {
                                    "text": "CustomerID"
                                },
                                "EmployeeID": {
                                    "text": "EmployeeID"
                                },
                                "OrderDate": {
                                    "text": "OrderDate"
                                }
                            }
                        }
                    }
                },
                "Customers": {
                    "text": "Customers",
                    "children": {
                        "Customer": {
                            "text": "Customer",
                            "children": {
                                "CompanyName": {
                                    "text": "CompanyName"
                                },
                                "FullAddress": {
                                    "text": "FullAddress",
                                    "children": {
                                        "Address": {
                                            "text": "Address"
                                        },
                                        "Region": {
                                            "text": "Region"
                                        },
                                        "PostalCode": {
                                            "text": "PostalCode"
                                        },
                                        "Country": {
                                            "text": "Country"
                                        },
                                        "City": {
                                            "text": "City"
                                        }
                                    }
                                },
                                "Phone": {
                                    "text": "Phone"
                                },
                                "Fax": {
                                    "text": "Fax"
                                },
                                "ContactName": {
                                    "text": "ContactName"
                                },
                                "ContactTitle": {
                                    "text": "ContactTitle"
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

这是我想要的输出:

"data": [{
        "text": "Root",
        "children": [{
                "text": "Orders",
                "children": [{
                        "text": "Order",
                        "children": [{
                                "text": "RequiredDate"
                            }, {
                                "text": "ShipInfo",
                                "children": [{
                                    "text": "ShipName"
                                }, {
                                    "text": "ShipCity"
                                }, {
                                    "text": "ShipAddress"
                                }, {
                                    "text": "ShipCity"
                                }, {
                                    "text": "ShipRegion"
                                }, {
                                    "text": "ShipPostcode"
                                }, {
                                    "text": "ShipCountry"
                                }]
                            }
                        }]
                }]
        }]
}]

有没有人对实现这一目标的最佳方法有任何想法?感谢任何答案!

编辑:这里要求的是代码..

的TreeModel

public class TreeNode {

    String id;
    String text;
    HashMap<String, TreeNode> children;

    public TreeNode(String text)
    {
        this.text = text;

    }

    @Override
    public String toString() {
        return "TreeModel [id=" + id + ", text=" + text + ", children="
                + children + "]";
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public HashMap<String, TreeNode> getChildren() {
        return children;
    }

    public void setChildren(HashMap<String, TreeNode> children) {
        this.children = children;
    }
}

守则

 File file = new File("xpaths.txt");

        try {
            BufferedReader br = new BufferedReader(new FileReader(file));

            TreeNode root = new TreeNode("Root");

            String currentLine;

            try {
                while((currentLine = br.readLine()) != null)
                {
                    XpathUtils.processXPath(currentLine, root);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }


            System.out.println(new Gson().toJson(root));

XpathUtils

   public static void processXPath(String xpath, TreeNode parent)
    {
        String[] elements = xpath.split("/");

        for(int i=0; i < elements.length; i ++)
        {
            parent = processElement(elements, parent, i);
        }
    }

    private static TreeNode processElement(
            String[] xpath, 
            TreeNode parent,
            int position)
    {
        if(parent.getChildren() == null)
        {
            parent.setChildren(new HashMap<String, TreeNode>());
        }

        if(!parent.getChildren().containsKey(xpath[position]))
        {
            TreeNode element = new TreeNode(xpath[position]);
            parent.getChildren().put(xpath[position], element);
            return element;
        } else {
            return parent.getChildren().get(xpath[position]);
        }
    }

编辑:短暂的休息后,我以新的视角回到了问题。看来问题很容易解决!基本上只是用ArrayList替换了HashMap,并添加了一些额外的方法来检查是否已经添加了XPath元素。可能不是最有效的方式,因为它每次循环数组,但它设法完成工作。

完成代码:

/**
     * Processes an XPath by splitting each element and 
     * adding them into individual @TreeNode objects.
     * 
     * @param xpath The XPath that is being processed
     * @param parent The top level parent @TreeNode 
     */
    public static void processXPath(String xpath, TreeNode parent) {
        String[] elements = xpath.split("/");

        for (int i = 0; i < elements.length; i++) {
            parent = processElement(elements, parent, i);
        }
    }

    /**
     * Add an element of an XPath  array to a @TreeNode object
     * firstly checking if the element already has a corresponding 
     * @TreeNode.
     * 
     * @param xpath The Xpath that is being processed
     * @param parent The parent TreeNode of the xpath element
     * @param position The the element is in the xpath array
     * @return
     */
    private static TreeNode processElement(String[] xpath, TreeNode parent,
            int position) {
        if (parent.getChildren() == null) {
            parent.setChildren(new ArrayList<TreeNode>());
        }

        if (doesNodeExist(xpath[position], parent.getChildren())) {
            return getExistingNode(xpath[position], parent.getChildren());

        } else {
            TreeNode element = new TreeNode(xpath[position]);
            parent.getChildren().add(element);

            return element;
        }
    }

    /**
     * Loop through the parent nodes children and returns a @Boolean
     * depicting if the node has already been added to the @ArrayList
     * 
     * @param element The name of the element that is being processed
     * @param children The list of children from the parent node
     * @return 
     */
    private static boolean doesNodeExist(String element,
            ArrayList<TreeNode> children) {
        for (TreeNode node : children) {
            if (node.getText().equals(element)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Loops through the parent nodes children and returns the 
     * @TreeNode object that was specified
     * 
     * @param element
     * @param children
     * @return
     */
    private static TreeNode getExistingNode(String element,
            ArrayList<TreeNode> children) {
        for (TreeNode node : children) {
            if (node.getText().equals(element)) {
                return node;
            }
        }

        return null;
    }

2 个答案:

答案 0 :(得分:0)

我使用具有以下属性的Node对象创建一个简单的树:

String pathElement

boolean isComplete // true if this is a complete path for cases where you have a path a/b and and a path a/b/x a would have this set to false, but b and x will have it set to true

List<Node> children

答案 1 :(得分:0)

如果您使用的是Java 8,则应该查看我的开源项目:unXmlunXml基本上从Xpath映射到Json属性。

可在Maven Central上找到。使用&gt;版本0.8.1,以获取递归的东西。

它使用Jackson进行Json处理。如果你需要,杰克逊可以优雅地映射到Objects

输入XML(简化,但Java代码也适用于您的xml)

<Root>
    <Orders>
        <Order>
            <CustomerID></CustomerID>
            <EmployeeID></EmployeeID>
        </Order>
    </Orders>
</Root>

Java代码

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.nerdforge.unxml.Parsing;
import com.nerdforge.unxml.factory.ParsingFactory;
import com.nerdforge.unxml.parsers.Parser;
import org.w3c.dom.Document;

class TreeParser {
    private Parsing parsing = ParsingFactory.getInstance().create();

    /**
     * This method will parse your XML, and return a Json ObjectNode
     */
    public ObjectNode parseXml(String inputXML){
        // get Xml as Document
        Document document = parsing.xml().document(inputXML);

        // create parser    
        Parser<ObjectNode> parser = parsing.obj()
            .attribute("data", "Root", recursiveParser())
            .build();

        return parser.apply(document);
    }

    public Parser<ObjectNode> recursiveParser(){
        return parsing.obj()
            .attribute("text", parsing.simple().nodeNameParser())
            .attribute("children",
                parsing.arr("node()", parsing.with(this::recursiveParser))
            ).build();
    }
}

输出JSON

{
    "data":{
        "children":[{
            "children":[{
                "children":[{
                    "children":[],
                    "text":"CustomerID"
                },{
                    "children":[],
                    "text":"EmployeeID"
                }],
                "text":"Order"
            }],
            "text":"Orders"
        }],
        "text":"Root"
    }
}