Есть ли в любом случае Узлы могут быть переупорядочены или удалены относительно узла элемента с помощью Java? - PullRequest
1 голос
/ 04 апреля 2020

Далее я хотел бы упорядочить узел <table>..</table> в соответствии со входом (inputY, inputX в этом случае) в атрибуте id или удалить <table>..</table>, если отправляется только один вход. Как я могу добиться этого с помощью парсера DOM.

<employees>
    <table>
        <employee>
            <id attr="inputY">
                <firstName>Lokesh</firstName>
                <lastName>Gupta</lastName>
                <department>
                    <id>101</id>
                    <name>IT</name>
                </department>
            </id>
        </employee>
    </table>
    <table>
        <employee>
            <id attr="inputX">
                <firstName>Brian</firstName>
                <lastName>Schultz</lastName>
                <department>
                    <id>102</id>
                    <name>HR</name>
                </department>
            </id>
        </employee>
    </table>
<employees>

Если ввод передается в порядке inputX и inputY, тогда XML будет выглядеть следующим образом:

<employees>
    <table>
        <employee>
            <id attr="inputX">
                <firstName>Brian</firstName>
                <lastName>Schultz</lastName>
                <department>
                    <id>102</id>
                    <name>HR</name>
                </department>
            </id>
        </employee>
    </table>
    <table>
        <employee>
            <id attr="inputY">
                <firstName>Lokesh</firstName>
                <lastName>Gupta</lastName>
                <department>
                    <id>101</id>
                    <name>IT</name>
                </department>
            </id>
        </employee>
    </table>
<employees>

Это то, что я сделал пока:

public static void main(String... args) throws Exception {
    DocumentBuilder db = DocumentBuilderFactory.newInstance().
            newDocumentBuilder();
    Document doc = db.parse("src/main/resources/some1.xml");
    doc.getDocumentElement().normalize();
    ArrayList<String> ids = new ArrayList<String>();
    ids.add("inputY");
    ids.add("inputX");
    Element root = doc.getDocumentElement();
    Node employees = root.getElementsByTagName("employees").item(0);
    NodeList moveList = doc.getElementsByTagName("table");
    for (int k = 0; k < moveList.getLength(); k++) {
        System.out.println(moveList.item(k));
        Node move = moveList.item(k);
        Element eMove = (Element) move;
        NodeList idList = eMove.getElementsByTagName("id");
        for (int i = 0; i < idList.getLength(); i++) {
            if (i < ids.size()) {
                boolean result = ids.contains(
                        idList.item(0).getAttributes().item(0).
                                getNodeValue());
                if (result) {
                    //System.out.println("parent node : " + move.getParentNode().getFirstChild());
                    Node currentFirstNode = employees.getFirstChild();
                    Node copyNode = move.cloneNode(true);
                    Node placeholder = currentFirstNode.getParentNode();
                    placeholder.insertBefore(copyNode,currentFirstNode);
                    placeholder.removeChild(move);
                }
            }
        }
    }
}

Обновление 2:

Вот мой новый код: Тем не менее он не может правильно упорядочить узлы. узел с атрибутом inputX находится перед inputZ, хотя у меня есть inputZ перед входом X в списке. Любое предложение?

DocumentBuilder db = DocumentBuilderFactory.newInstance().
                newDocumentBuilder();
        Document doc = db.parse("src/main/resources/some1.xml");
        doc.getDocumentElement().normalize();

        ArrayList<String> ids = new ArrayList<String>();
        ids.add("inputZ");
        ids.add("inputX");
        Element root = doc.getDocumentElement();
        Node employees = root.getElementsByTagName("employees").item(0);
        NodeList moveList = doc.getElementsByTagName("table");
        for (int k = 0; k < moveList.getLength(); k++) {
            System.out.println("# of table nodes : " + moveList.getLength());
            Node move = moveList.item(k);
            Element eMove = (Element) move;
            NodeList idList = eMove.getElementsByTagName("id");
                System.out.println("id attribute : " + idList.item(0).getAttributes().item(0));
                    boolean result = ids.contains(
                            idList.item(0).getAttributes().item(0).
                                    getNodeValue());
                    if (result) {
                        System.out.println(result);
                        Node currentFirstNode = employees.getFirstChild();
                        Node placeholder = currentFirstNode.getParentNode();
                        placeholder.insertBefore(move, currentFirstNode);
                    } else {
                        System.out.println(result);
                        System.out.println("Employees child node : " + employees.getChildNodes());
                        employees.removeChild(move);
                    }
        }

XML:

<root>
    <employees>
        <table>
            <employee>
                <id attr="inputZ">
                    <firstName>Ben</firstName>
                    <lastName>Smith</lastName>
                    <department>
                        <id>103</id>
                        <name>Business</name>
                    </department>
                </id>
            </employee>
        </table>
        <table>
            <employee>
                <id attr="inputX">
                    <firstName>Brian</firstName>
                    <lastName>Schultz</lastName>
                    <department>
                        <id>102</id>
                        <name>HR</name>
                    </department>
                </id>
            </employee>
        </table>
        <table>
            <employee>
                <id attr="inputY">
                    <firstName>Lokesh</firstName>
                    <lastName>Gupta</lastName>
                    <department>
                        <id>101</id>
                        <name>IT</name>
                    </department>
                </id>
            </employee>
        </table>
    </employees>
</root>

Ответы [ 2 ]

1 голос
/ 05 апреля 2020

Вы можете сделать это так:

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class Test {
    public static void main(String[] args) throws Exception {
        // Load XML file into DOM tree and verify root element name
        Element root = DocumentBuilderFactory.newInstance()
                .newDocumentBuilder()
                .parse("test.xml")
                .getDocumentElement();
        if (! root.getTagName().equals("employees"))
            throw new IllegalArgumentException("Invalid root element name: " + root.getTagName());

        // Locate all <table> elements, identify "inputX" and "inputY" tables, and their relative order
        boolean inputYBeforeInputX = false;
        Node inputX = null, inputY = null;
        List<Node> toBeRemoved = new ArrayList<>();
        for (Node child = root.getFirstChild(); child != null; child = child.getNextSibling()) {
            if (child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals("table")) {
                String id = getFirstChildByTagName(child, "employee")
                        .flatMap(e -> getFirstChildByTagName(e, "id"))
                        .map(e -> e.getAttribute("attr"))
                        .orElse(null);
                if (inputX == null && "inputX".equals(id)) {
                    inputX = child;
                } else if (inputY == null && "inputY".equals(id)) {
                    inputY = child;
                    inputYBeforeInputX = (inputX == null);
                } else {
                    toBeRemoved.add(child);
                }
            }
        }

        // If only one of "inputX" and "inputY" was found, mark it to be removed
        if (inputX != null && inputY == null)
            toBeRemoved.add(inputX);
        else if (inputY != null && inputX == null)
            toBeRemoved.add(inputY);

        // Remove superfluous <table> elements
        for (Node nodeToRemove : toBeRemoved)
            root.removeChild(nodeToRemove);

        // Swap "inputX" and "inputY" if "inputY" was before "inputX"
        if (inputYBeforeInputX && inputX != null && inputY != null) {
            if (inputY.getNextSibling() == inputX) {
                root.insertBefore(inputX, inputY);
            } else {
                Node inputXnext = inputX.getNextSibling();
                root.insertBefore(inputX, inputY.getNextSibling());
                root.insertBefore(inputY, inputXnext);
            }
        }

        // Print result XML
        TransformerFactory.newInstance()
                .newTransformer()
                .transform(new DOMSource(root), new StreamResult(System.out));
    }
    private static Optional<Element> getFirstChildByTagName(Node parent, String tagName) {
        for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling())
            if (child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals(tagName))
                return Optional.of((Element) child);
        return Optional.empty();
    }
}
0 голосов
/ 05 апреля 2020

Вы говорите «используя Java», но, безусловно, самый простой способ сделать это - использовать XSLT, и, конечно, его можно легко вызвать из Java.

. сделать это достаточно легко даже в XSLT 1.0:

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
  <employees>
    <xsl:for-each select="employees/table">
      <xsl:sort select="employee/id/@attr">
      <xsl:copy-of select="."/>
    </xsl:for-each>
  </employees>
</xsl:template>

</xsl:transform>

Боюсь, я не понимаю, что вы подразумеваете под этой частью требования: «или удалить… если отправлен только один вход».

...