有没有办法使用Java相对于元素节点重新排序或删除节点?

huangapple go评论78阅读模式
英文:

Is there anyway Nodes can be re-ordered or removed relative to an element node using Java?

问题

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("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++) {
        Node move = moveList.item(k);
        Element eMove = (Element) move;
        NodeList idList = eMove.getElementsByTagName("id");
        boolean result = ids.contains(
            idList.item(0).getAttributes().item(0).getNodeValue()
        );
        
        if (result) {
            Node currentFirstNode = employees.getFirstChild();
            Node placeholder = currentFirstNode.getParentNode();
            placeholder.insertBefore(move, currentFirstNode);
        } else {
            employees.removeChild(move);
        }
    }
}

Please note that I've only provided the translated code without comments and additional explanations. Let me know if you need further assistance!

英文:

In the following I would like to order the &lt;table&gt;..&lt;/table&gt; node according to the input (inputY, inputX in this case) in id attribute or remove &lt;table&gt;..&lt;/table&gt; if only one input is sent. How can I achieve it using DOM parser.

<!-- language: xml -->

&lt;employees&gt;
	&lt;table&gt;
		&lt;employee&gt;
			&lt;id attr=&quot;inputY&quot;&gt;
				&lt;firstName&gt;Lokesh&lt;/firstName&gt;
				&lt;lastName&gt;Gupta&lt;/lastName&gt;
				&lt;department&gt;
					&lt;id&gt;101&lt;/id&gt;
					&lt;name&gt;IT&lt;/name&gt;
				&lt;/department&gt;
			&lt;/id&gt;
		&lt;/employee&gt;
	&lt;/table&gt;
	&lt;table&gt;
		&lt;employee&gt;
			&lt;id attr=&quot;inputX&quot;&gt;
				&lt;firstName&gt;Brian&lt;/firstName&gt;
				&lt;lastName&gt;Schultz&lt;/lastName&gt;
				&lt;department&gt;
					&lt;id&gt;102&lt;/id&gt;
					&lt;name&gt;HR&lt;/name&gt;
				&lt;/department&gt;
			&lt;/id&gt;
		&lt;/employee&gt;
	&lt;/table&gt;
&lt;employees&gt;

If input is passed in the order of inputX and inputY then the XML would be like the following :

<!-- language: xml -->

&lt;employees&gt;
	&lt;table&gt;
		&lt;employee&gt;
			&lt;id attr=&quot;inputX&quot;&gt;
				&lt;firstName&gt;Brian&lt;/firstName&gt;
				&lt;lastName&gt;Schultz&lt;/lastName&gt;
				&lt;department&gt;
					&lt;id&gt;102&lt;/id&gt;
					&lt;name&gt;HR&lt;/name&gt;
				&lt;/department&gt;
			&lt;/id&gt;
		&lt;/employee&gt;
	&lt;/table&gt;
	&lt;table&gt;
		&lt;employee&gt;
			&lt;id attr=&quot;inputY&quot;&gt;
				&lt;firstName&gt;Lokesh&lt;/firstName&gt;
				&lt;lastName&gt;Gupta&lt;/lastName&gt;
				&lt;department&gt;
					&lt;id&gt;101&lt;/id&gt;
					&lt;name&gt;IT&lt;/name&gt;
				&lt;/department&gt;
			&lt;/id&gt;
		&lt;/employee&gt;
	&lt;/table&gt;
&lt;employees&gt;

This is what I have done so far :

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

Update 2:

Here is my new code: Still it fails to order the nodes properly. <id> node with attribute inputX comes before inputZ, even though I have inputZ before input X in the list. Any suggestion?

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

        ArrayList&lt;String&gt; ids = new ArrayList&lt;String&gt;();
        ids.add(&quot;inputZ&quot;);
        ids.add(&quot;inputX&quot;);
        Element root = doc.getDocumentElement();
        Node employees = root.getElementsByTagName(&quot;employees&quot;).item(0);
        NodeList moveList = doc.getElementsByTagName(&quot;table&quot;);
        for (int k = 0; k &lt; moveList.getLength(); k++) {
            System.out.println(&quot;# of table nodes : &quot; + moveList.getLength());
            Node move = moveList.item(k);
            Element eMove = (Element) move;
            NodeList idList = eMove.getElementsByTagName(&quot;id&quot;);
                System.out.println(&quot;id attribute : &quot; + 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(&quot;Employees child node : &quot; + employees.getChildNodes());
                        employees.removeChild(move);
                    }
        }

XML :

&lt;root&gt;
    &lt;employees&gt;
        &lt;table&gt;
            &lt;employee&gt;
                &lt;id attr=&quot;inputZ&quot;&gt;
                    &lt;firstName&gt;Ben&lt;/firstName&gt;
                    &lt;lastName&gt;Smith&lt;/lastName&gt;
                    &lt;department&gt;
                        &lt;id&gt;103&lt;/id&gt;
                        &lt;name&gt;Business&lt;/name&gt;
                    &lt;/department&gt;
                &lt;/id&gt;
            &lt;/employee&gt;
        &lt;/table&gt;
        &lt;table&gt;
            &lt;employee&gt;
                &lt;id attr=&quot;inputX&quot;&gt;
                    &lt;firstName&gt;Brian&lt;/firstName&gt;
                    &lt;lastName&gt;Schultz&lt;/lastName&gt;
                    &lt;department&gt;
                        &lt;id&gt;102&lt;/id&gt;
                        &lt;name&gt;HR&lt;/name&gt;
                    &lt;/department&gt;
                &lt;/id&gt;
            &lt;/employee&gt;
        &lt;/table&gt;
        &lt;table&gt;
            &lt;employee&gt;
                &lt;id attr=&quot;inputY&quot;&gt;
                    &lt;firstName&gt;Lokesh&lt;/firstName&gt;
                    &lt;lastName&gt;Gupta&lt;/lastName&gt;
                    &lt;department&gt;
                        &lt;id&gt;101&lt;/id&gt;
                        &lt;name&gt;IT&lt;/name&gt;
                    &lt;/department&gt;
                &lt;/id&gt;
            &lt;/employee&gt;
        &lt;/table&gt;
    &lt;/employees&gt;
&lt;/root&gt;

答案1

得分: 1

你可以像这样做:

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 {
        // 将XML文件加载到DOM树中并验证根元素名称
        Element root = DocumentBuilderFactory.newInstance()
            .newDocumentBuilder()
            .parse("test.xml")
            .getDocumentElement();
        if (!root.getTagName().equals("employees"))
            throw new IllegalArgumentException("无效的根元素名称:" + root.getTagName());

        // 定位所有的<table>元素,识别"inputX"和"inputY"表,并确定它们的相对顺序
        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);
                }
            }
        }

        // 如果只找到"inputX"或"inputY"中的一个,标记它以便移除
        if (inputX != null && inputY == null)
            toBeRemoved.add(inputX);
        else if (inputY != null && inputX == null)
            toBeRemoved.add(inputY);

        // 移除多余的<table>元素
        for (Node nodeToRemove : toBeRemoved)
            root.removeChild(nodeToRemove);

        // 如果"inputY"在"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);
            }
        }

        // 打印结果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();
    }
}
英文:

You can do it like this:

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(&quot;test.xml&quot;)
.getDocumentElement();
if (! root.getTagName().equals(&quot;employees&quot;))
throw new IllegalArgumentException(&quot;Invalid root element name: &quot; + root.getTagName());
// Locate all &lt;table&gt; elements, identify &quot;inputX&quot; and &quot;inputY&quot; tables, and their relative order
boolean inputYBeforeInputX = false;
Node inputX = null, inputY = null;
List&lt;Node&gt; toBeRemoved = new ArrayList&lt;&gt;();
for (Node child = root.getFirstChild(); child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE &amp;&amp; child.getNodeName().equals(&quot;table&quot;)) {
String id = getFirstChildByTagName(child, &quot;employee&quot;)
.flatMap(e -&gt; getFirstChildByTagName(e, &quot;id&quot;))
.map(e -&gt; e.getAttribute(&quot;attr&quot;))
.orElse(null);
if (inputX == null &amp;&amp; &quot;inputX&quot;.equals(id)) {
inputX = child;
} else if (inputY == null &amp;&amp; &quot;inputY&quot;.equals(id)) {
inputY = child;
inputYBeforeInputX = (inputX == null);
} else {
toBeRemoved.add(child);
}
}
}
// If only one of &quot;inputX&quot; and &quot;inputY&quot; was found, mark it to be removed
if (inputX != null &amp;&amp; inputY == null)
toBeRemoved.add(inputX);
else if (inputY != null &amp;&amp; inputX == null)
toBeRemoved.add(inputY);
// Remove superfluous &lt;table&gt; elements
for (Node nodeToRemove : toBeRemoved)
root.removeChild(nodeToRemove);
// Swap &quot;inputX&quot; and &quot;inputY&quot; if &quot;inputY&quot; was before &quot;inputX&quot;
if (inputYBeforeInputX &amp;&amp; inputX != null &amp;&amp; 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&lt;Element&gt; getFirstChildByTagName(Node parent, String tagName) {
for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling())
if (child.getNodeType() == Node.ELEMENT_NODE &amp;&amp; child.getNodeName().equals(tagName))
return Optional.of((Element) child);
return Optional.empty();
}
}

答案2

得分: 0

你说“使用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>

对于您提到的需求中的这部分内容:“或者如果只发送一个输入,则删除..”,我不太理解你的意思。

英文:

You say "using Java", but by far the easiest way to do this sort of thing is using XSLT, and of course that can easily be invoked from Java.

This one can be done easily enough even in XSLT 1.0:

&lt;xsl:transform version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
&lt;xsl:template match=&quot;/&quot;&gt;
&lt;employees&gt;
&lt;xsl:for-each select=&quot;employees/table&quot;&gt;
&lt;xsl:sort select=&quot;employee/id/@attr&quot;&gt;
&lt;xsl:copy-of select=&quot;.&quot;/&gt;
&lt;/xsl:for-each&gt;
&lt;/employees&gt;
&lt;/xsl:template&gt;
&lt;/xsl:transform&gt;

I'm afraid I don't understand what you mean by this part of the requirement: "or remove .. if only one input is sent".

huangapple
  • 本文由 发表于 2020年4月5日 04:34:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/61034424.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定