使用DOM编辑XML文档

来源:互联网 发布:数据报表展示解决方案 编辑:程序博客网 时间:2024/05/19 03:26

更改节点的值

检查一下 XML 文档的常量是有用的,但是在处理全功能的应用程序时,您可能需要更改数据以添加、编辑、移动或删除信息。编辑数据的能力对创建新 XML 文档的过程也是至关重要的。这类更改中最简单的情况就是更改元素的文本内容。

这里的目标是更改某个元素的文本节点的值,在此例中是将每个 orderstatus 设置为“processed”,然后向屏幕打印新的值。

changeOrder()方法的调用使用起始节点(root)以及要更改的元素名称和要更改到的目标值作为参数。

changeOrder()首先检查节点的名称,以确定它是否为要编辑的元素之一。如果是,应用程序需要更改的不是这个节点的值,而是这个节点的第一个孩子的值,因为这第一个孩子才是实际包含内容的文本节点。

在任一种情况下,应用程序都要检查每个孩子,就像大它在第一次单步调试文档时所做一样。

当完成更改时,更改后的值将使用 getElementsByTagName() 来检查。这个方法返回具有指定名称(比如 status)的所有孩子的列表。然后应用程序就能够检查该列表中的值,以检验 changeOrder() 方法调用的有效性。

...public class OrderProcessor {   private static void changeOrder (Node start,                                String elemName,                               String elemValue)   {      if (start.getNodeName().equals(elemName)) {         start.getFirstChild().setNodeValue(elemValue);      }               for (Node child = start.getFirstChild();           child != null;          child = child.getNextSibling())      {          changeOrder(child, elemName, elemValue);      }   }...   public static void main (String args[]) {...           // Change text content      changeOrder(root, "status", "processing");      NodeList orders = root.getElementsByTagName("status");      for (int orderNum = 0;            orderNum < orders.getLength();            orderNum++)       {          System.out.println(orders.item(orderNum)                   .getFirstChild().getNodeValue());      }   }}
添加节点:准备数据
与更改现有节点不同,有时添加一个节点是必要的,而您可以通过多种方式来做到这点。在本例中,应用程序汇总
每个 order 的价格,然后添加一个 total 元素。它通过接受每个订单,循环迭代它的每件商品以获取商品价
格,然后汇总这些价格,从而获得总价格。然后应用程序向订单添加一个新的元素(参加下面的代码清单)。
首先,应用程序检索 order 元素,就像它检索 status 元素一样。然后它循环迭代这其中的每个元素。
对于这其中的每个 order,应用程序都需要其 item 元素的一个 NodeList,因此应用程序必须首先
order Node强制转换为 Element,才能使用getElementsByTagName()
然后应用程序可以循环迭代 item 元素,以寻找选定的 order。应用程序将每个 item 强制转换为 
Element,以便能够根据名称检索 priceqty。它是通过使用 getElementsByTagName()
来进行的,因为每件商品只有一个名称,它可以直接转到 item(0),即结果 NodeList 中的第一个
条目。这第一个条目表示 price(或 qty)元素。它就是从那里获得文本节点的值的。
文本节点的值是 String 值,应用程序然后会将它转换为一个 double 值,以允许进行必要的数学运算。
当应用程序检查完每个订单的每件商品时,total 就是一个代表总价格的 double 值。然后 total 
被转换为 String值,以便能将它用作新元素的内容,<total> 最终加入了 order
...changeOrder(root, "status", "processing");NodeList orders = root.getElementsByTagName("order");for (int orderNum = 0;      orderNum < orders.getLength();      orderNum++) {   Element thisOrder = (Element)orders.item(orderNum);   NodeList orderItems = thisOrder.getElementsByTagName("item");   double total = 0;   for (int itemNum = 0;        itemNum < orderItems.getLength();        itemNum++) {      // Total up cost for each item and       // add to the order total          //Get this item as an Element        Element thisOrderItem = (Element)orderItems.item(itemNum);        //Get pricing information for this Item        String thisPrice =                      thisOrderItem.getElementsByTagName("price").item(0)                                        .getFirstChild().getNodeValue();        double thisPriceDbl = new Double(thisPrice).doubleValue();        //Get quantity information for this Item        String thisQty =                      thisOrderItem.getElementsByTagName("qty").item(0)                                      .getFirstChild().getNodeValue();        double thisQtyDbl = new Double(thisQty).doubleValue();        double thisItemTotal = thisPriceDbl*thisQtyDbl;        total = total + thisItemTotal;    }    String totalString = new Double(total).toString();}...添加节点:向文档添加节点
您可以用许多方法创建新 Node,而本例将使用其中的几种方法。 首先,Document 对象能够使用 
totalString 作为值来创建新的文本节点。新的Node现在已经存在了,但是还没在任何地方实际
连接到 Document。新的 total 元素是以类似的方式创建的,起初也没有实质性的内容。
添加节点的另一种方法是使用 appendChild(),就像这里将节点添加到 total元素一样。
最后,应用程序可以使用 insertBefore() 来向 Document 添加新的元素,同时指定新的 
Node,然后指定新 Node 之后的那个 Node
单步调试文档将检验这些更改。
...changeOrder(root, "status", "processing");NodeList orders = root.getElementsByTagName("order");for (int orderNum = 0;      orderNum < orders.getLength();      orderNum++) {...    String totalString = new Double(total).toString();    Node totalNode = doc.createTextNode(totalString);      Element totalElement = doc.createElement("total");    totalElement.appendChild(totalNode);      thisOrder.insertBefore(totalElement, thisOrder.getFirstChild());}stepThrough(root);     ...删除节点
与替换元素的文本不同,应用程序可以将它一起删除。在这个例子中,应用程序检查商品是否有现货
。如果没有,它将从订单中删除该商品,而不是将其添加到汇总中。
在将商品成本添加到价款汇总中之前,应用程序会检查 instock 属性的值。如果该值为 N,则不
是将它添加到价款汇总中,而是将它完全删除。为此,它使用了 removeChild() 方法,不过首
先使用了 getParentNode() 来确定 orderItem 的父节点。实际的 Node 从文档中删除了
,但是该方法还是将它作为一个对象返回,以便能根据需要移动它。
...   //Get this item as an Element   Element thisOrderItem = (Element)orderItems.item(itemNum);  if (thisOrderItem.getAttributeNode("instock")                  .getNodeValue().equals("N")) {      Node deadNode =                  thisOrderItem.getParentNode().removeChild(thisOrderItem);   } else {      //Get pricing information for this Item      String thisPrice =                    thisOrderItem.getElementsByTagName("price").item(0)                                      .getFirstChild().getNodeValue();...      total = total + thisItemTotal;   }}String totalString = new Double(total).toString();...替换节点
因为某件商品订货不足(backordered)而删除该商品是没有多大意义的。相反,应用程序会使用
一个 backordered 项来替换它。
与使用 removeChild() 不同的是,应用程序简单地使用了replaceChild()。注意在此例
中,该方法还会返回旧的节点,以便能根据需要将它移往别处,或许是移到一个新 Document
该 Document 列出所有订单不足的商品。

注意由于没有内容被添加到该元素,因此它是一个空元素。空元素没有内容,并且可以用一种特殊的简
写来表示:

<backordered />

斜线(/)消除了对结束标签(</backordered>)的需要。

...   if (thisOrderItem.getAttributeNode("instock")                  .getNodeValue().equals("N")) {      Element backElement = doc.createElement("backordered");      Node deadNode = thisOrderItem.getParentNode()                .replaceChild(backElement,  thisOrderItem);   } else {...创建和设置属性
没有标志表明一个 backordered 元素是什么商品,那该怎么正确处理它呢?纠正信息缺乏的方法之一
是向元素添加属性。

应用程序首先创建一个 itemid 属性。接下来,它根据原先的 item 元素确定 itemid 的值,然后
再自己设置该属性的值。最后,它把该元素添加到文档,就像以前一样。

...if (thisOrderItem.getAttributeNode("instock")                  .getNodeValue().equals("N")) {   Element backElement = doc.createElement("backordered");   backElement.setAttributeNode(doc.createAttribute("itemid"));      String itemIdString =               thisOrderItem.getAttributeNode("itemid").getNodeValue();   backElement.setAttribute("itemid", itemIdString);   Node deadNode = thisOrderItem.getParentNode().replaceChild(backElement,                                                        thisOrderItem);} else {...如果具有该名称的节点不存在, setAttribute() 就会创建一个属性节点。
删除属性
 

应用程序还可以删除属性。例如,在输出中显示客户信用限额信息也许是不可取的,因此应用程序可以
临时地将该属性从文档中删除。

删除信息是相当简单的,只需使用 removeAttribute() 来删除数据。

...Element thisOrder = (Element)orders.item(orderNum);  Element customer =        (Element)thisOrder.getElementsByTagName("customerid")                                     .item(0);customer.removeAttribute("limit");    NodeList orderItems = thisOrder.getElementsByTagName("item");...
原创粉丝点击