- 浏览: 49631 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
ldbin:
请问连接mysql的时候出现中文乱码问题怎么解决?不用连接池就 ...
apache连接池使用 -
cucumber:
2.3.3配合spring2.5.5可以默认支持了
ibatis配置支持通配符 -
FAT0708:
iBATIS引入SqlMap的顺序,被引入的片段,要优先于欲引 ...
ibatis配置支持通配符 -
超级潜水员:
如果是使用spring 2.5.5,直接使用
&l ...
ibatis配置支持通配符 -
FAT0708:
cnpollux 写道比如一个SqlMap xml文件依赖于另 ...
ibatis配置支持通配符
以下资料均来自于www.ibm.com.cn
1、将文件解析为文档
三步过程
为了使用 XML 文件中的信息,必须解析文件以创建一个 Document 对象。
Document 对象是一个接口,因而不能直接将它实例化;一般情况下,应用程序会相应使用一个工厂。准确的过程因实现而异,但是基本思想是相同的。(同样,Level 3 标准化了这个任务)。在这个例子 Java 环境中,解析文件是一个三步过程:
1. 创建 DocumentBuilderFactory。DocumentBuilderFactory 对象创建 DocumentBuilder。
2. 创建 DocumentBuilder。DocumentBuilder 执行实际的解析以创建 Document 对象。
3. 解析文件以创建 Document 对象。
现在您可以开始构建应用程序了。
Java 的 DOM Level 2 实现允许通过以下方法控制解析器的参数:
* setCoalescing():决定解析器是否要将 CDATA 节点转换为文本,以及是否要和周围的文本节点合并(如果适用的话)。其默认值为 false。
* setExpandEntityReferences():确定是否要展开外部实体引用。如果为 true,外部数据将插入文档。其默认值为 true。(请参阅 参考资料 以了解关于使用外部实体的技巧)。
* setIgnoringComments():确定是否要忽略文件中的注释。其默认值为 false。
* setIgnoringElementContentWhitespace():确定是否要忽略元素内容中的空白(类似于浏览器对待 HTML 的方式)。其默认值为 false。
* setNamespaceAware():确定解析器是否要注意名称空间信息。其默认值为 false。
* setValidating():默认情况下,解析器不验证文档。将这个参数设置为 true 可打开验证功能。
2、获取根元素
一旦解析了文档并创建了一个 Document,应用程序就能单步调试该结构以审核、查找或显示信息。这种导航功能是将要在 Document 上执行的许多操作的基础。
对文档的单步调试首先从根元素开始。格式良好的文档仅有一个根元素,也称为 DocumentElement。应用程序首先检索这个元素。
3、获取节点的孩子
一旦应用程序确定了根元素,它就把根元素的孩子的列表作为一个 NodeList 来检索。NodeList 类是一系列的项,应用程序将逐个迭代这些项。 在本例中,为简洁起见,应用程序通过仅显示有多少元素出现在生成的 NodeList 中,从而获取孩子节点和验证检索结果。
使用 getFirstChild() 和 getNextSibling()
父子和兄弟关系提供了迭代某个节点的所有孩子的替代方法,它在某些场合下可能更为适宜,比如在这些关系和孩子的出现顺序对理解数据至关重要的时候。
在 Step 3 中,for 循环首先从根元素的第一个孩子开始。应用程序迭代第一个孩子的所有兄弟,直至已全部对它们求值。
每次应用程序执行该循环,它都要检索一个 Node 对象,输出其名称和值。注意 orders 的五个孩子包括 orders 元素和三个文本节点。还要注意元素具有一个 null 值,而不是预期的文本。包含实际内容作为其值的,是作为元素的孩子的文本节点。
4、编辑文档
更改节点的值
检查一下 XML 文档内容的常量是有用的,但是在处理全功能的应用程序时,您可能需要更改数据以添加、编辑、移动或删除信息。编辑数据的能力对创建新 XML 文档的过程也是至关重要的。这类更改中最简单的情况就是更改元素的文本内容。
这里的目标是更改某个元素的文本节点的值,在此例中是将每个 order 的 status 设置为 “processed”,然后向屏幕输出新的值。
使用起始节点(root)以及要更改的元素名称和要更改到的目标值作为参数,调用 changeOrder() 方法。
changeOrder() 首先检查节点的名称,以确定它是否为要编辑的元素之一。如果是,应用程序需要更改的不是这个节点的值,而是这个节点的第一个孩子的值,因为这第一个孩子才是实际包含内容的文本节点。
在任一种情况下,应用程序都要检查每个孩子,就像它在第一次单步调试文档时一样。
当完成更改时,更改后的值将使用 getElementsByTagName() 来检查。这个方法返回具有指定名称(比如 status)的所有孩子的列表。然后应用程序就能够检查该列表中的值,以检验 changeOrder() 方法调用的有效性。
添加节点:准备数据
与更改现有节点不同,有时添加一个节点是必要的,而您可以通过多种方式来做到这点。在本例中,应用程序汇总每个 order 的价格,然后添加一个 total 元素。它通过接受每个订单,循环迭代它的每件商品以获取商品价格,然后汇总这些价格,从而获得总价格。然后应用程序向订单添加一个新的元素(参见下面的代码清单)。
首先,应用程序检索 order 元素,就像它检索 status 元素一样。然后它循环迭代这其中的每个元素。
对于这其中的每个 order,应用程序都需要其 item 元素的一个 NodeList,因此应用程序必须首先将 order Node 强制转换为 Element,才能使用 getElementsByTagName()。
然后应用程序可以循环迭代 item 元素,以寻找选定的 order。应用程序将每个 item 强制转换为 Element,以便能够根据名称检索 price 和 qty。它是通过使用 getElementsByTagName() 来实现的。因为每件商品只有一个名称,它可以直接转到 item(0),即生成的 NodeList 中的第一个条目。这第一个条目表示 price(或 qty)元素。它就是从那里获得文本节点的值的。
文本节点的值是 String 值,应用程序然后会将它转换为一个 double 值,以允许进行必要的数学运算。
当应用程序检查完每个订单的每件商品时,total 就是一个代表总价格的 double 值。然后 total 被转换为 String 值,以便能将它用作新元素的内容,<total> 最终加入了 order。
添加节点:向文档添加节点
您可以用许多方法创建新 Node,而本例将使用其中的几种方法。首先,Document 对象能够创建新的值为 totalString 的文本节点。新的 Node 现在已经存在了,但是还没在任何地方实际连接到 Document。新的 total 元素是以类似的方式创建的,起初也没有实质性的内容。
添加节点的另一种方法是使用 appendChild(),就像这里将节点添加到新的 total 元素一样。
最后,应用程序可以使用 insertBefore() 来向 Document 添加新的元素,同时指定新的 Node,然后指定新 Node 之后的那个 Node。
单步调试文档将检验这些更改。
删除节点
应用程序不是替换元素的文本,而是将它完全删除。在这个例子中,应用程序检查商品是否有现货。如果没有,它将从订单中删除该商品,而不是将其添加到汇总中。
在将商品成本添加到价款汇总中之前,应用程序会检查 instock 属性的值。如果该值为 N,则不是将它添加到价款汇总中,而是将它完全删除。为此,它使用了 removeChild() 方法,不过首先要使用 getParentNode() 来确定 orderItem 的父节点。实际的 Node 已从文档中删除,但是该方法还是将它作为一个对象返回,以便能根据需要移动它。
替换节点
当然,因为某件商品订货不足(backordered)而删除该商品是没有多大意义的。相反,应用程序会使用一个 backordered 项来替换它。
应用程序并不使用 removeChild(),而是简单地使用了replaceChild()。注意在此示例中,该方法还会返回旧的节点,以便能根据需要将它移往别处,或许可以移动到一个新 Document,它列出了所有订单不足的商品。
注意由于没有内容被添加到该元素,因此它是一个空元素。空元素没有内容,并且可以用一种特殊的简写来表示:
<backordered />
有了斜线(/),就不再需要结束标签(</backordered>)。
创建和设置属性
那么,如果没有标志表明一个 backordered 元素是什么商品,那该怎么正确处理它呢?纠正信息缺乏的方法之一是向元素添加属性。
应用程序首先创建一个 itemid 属性。接下来,它根据原先的 item 元素确定 itemid 的值,然后再自己设置该属性的值。最后,它把该元素添加到文档,就像以前一样。
删除属性
应用程序还可以删除属性。例如,在输出中显示客户信用限额信息也许是不可取的,因此应用程序可以临时地将该属性从文档中删除。
删除信息是相当简单的,只需使用 removeAttribute() 来删除数据。
5、
输出文档
准备数据
到目前为止,本教程已考察了如何接受、使用和操作 XML 数据。要完成这个周期,您还必须能够输出 XML。
对于本教程中的情况,目标输出是一个文件,该文件简单地列出每个订单、依据客户信用限额来确定的订单处理情况,以及 customerid。
<?xml version="1.0" encoding="UTF-8"?>
<processedOrders>
<order>
<status>PROCESSED</status>
<customerid>2341</customerid>
<amount>874.00</amount>
</order>
<order>
<status>REJECTED</status>
<customerid>251222</customerid>
<amount>200.00</amount>
</order>
</processedOrders>
应用程序首先创建要输出的 Document 对象。为方便起见,可以使用创建原先的 Document 的 DocumentBuilder 来创建新的 Document 对象。
...
public static void main (String args[]) {
File docFile = new File("orders.xml");
Document doc = null;
Document newdoc = null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(docFile);
newdoc = db.newDocument();
} catch (Exception e) {
System.out.print("Problem parsing the file: "+e.getMessage());
}
...
thisOrder.insertBefore(totalElement, thisOrder.getFirstChild());
}
Element newRoot = newdoc.createElement("processedOrders");
NodeList processOrders = doc.getElementsByTagName("order");
for (int orderNum = 0;
orderNum < processOrders.getLength();
orderNum++) {
Element thisOrder = (Element)processOrders.item(orderNum);
Element customerid =
(Element)thisOrder.getElementsByTagName("customerid")
.item(0);
String limit = customerid.getAttributeNode("limit").getNodeValue();
String total = thisOrder.getElementsByTagName("total").item(0)
.getFirstChild().getNodeValue();
double limitDbl = new Double(limit).doubleValue();
double totalDbl = new Double(total).doubleValue();
Element newOrder = newdoc.createElement("order");
Element newStatus = newdoc.createElement("status");
if (totalDbl > limitDbl) {
newStatus.appendChild(newdoc.createTextNode("REJECTED"));
} else {
newStatus.appendChild(newdoc.createTextNode("PROCESSED"));
}
Element newCustomer = newdoc.createElement("customerid");
String oldCustomer = customerid.getFirstChild().getNodeValue();
newCustomer.appendChild(newdoc.createTextNode(oldCustomer));
Element newTotal = newdoc.createElement("total");
newTotal.appendChild(newdoc.createTextNode(total));
newOrder.appendChild(newStatus);
newOrder.appendChild(newCustomer);
newOrder.appendChild(newTotal);
newRoot.appendChild(newOrder);
}
newdoc.appendChild(newRoot);
System.out.print(newRoot.toString());
...
在处理 orders.xml 之后,应用程序创建了一个新的元素 processedOrders,这个新的元素最终将成为新文档的根元素。然后它遍历每个订单。对于每个订单,它都提取其 total 和 limit 信息。
接下来,应用程序为订单创建新元素:order、status、customerid 和 amount。它根据汇总款项是否超过客户的信用限额来填充 status,然后相应地填充其他元素。
一旦应用程序为订单创建了元素,它就必须将这些元素整合起来。它首先向新的 order 元素添加状态、客户信息和汇总款项。然后它把新的 order 添加到 newRoot 元素。
尽管如此,newRoot 元素并没有实际连接到某个父节点。当应用程序完成所有订单的处理时,newRoot 就被追加到新的文档。
最后,应用程序将 newRoot 转换为一个 String,并简单地将它发送到 System.out,从而输出数据。
标准化文档
注意:在节点上,一些版本的 Java 代码不支持这个版本的 toString()。如果出现这种情况,使用 恒等转换 中展示的技巧就可以查看节点的内容。
创建 XML 文件
现在应用程序已经创建了新的信息,将这个信息输出到某个文件是很简单的。
对数据也使用了相同的逻辑,只不过应用程序不是将它输出到屏幕,而是将它输出到一个文件。
要注意的一件重要事情是,由于 XML 数据是文本,因此可以通过任何方式来对它进行格式化。例如,您可以创建 stepThroughAll() 的变体,它将创建缩进的或完美输出的版本。记住,这将创建额外的空白(文本)节点。
...
import java.io.FileWriter;
...
try
{
File newFile = new File("processedOrders.xml");
FileWriter newFileStream = new FileWriter(newFile);
newFileStream.write ("<?xml version=\"1.0\"?>");
newFileStream.write ("<!DOCTYPE
"+doc.getDoctype().getName()+" ");
if (doc.getDoctype().getSystemId() != null) {
newFileStream.write (" SYSTEM ");
newFileStream.write (doc.getDoctype().getSystemId());
}
if (doc.getDoctype().getPublicId() != null) {
newFileStream.write (" PUBLIC ");
newFileStream.write (doc.getDoctype().getPublicId());
}
newFileStream.write (">");
newFileStream.write (newRoot.toString());
newFileStream.close();
} catch (IOException e) {
System.out.println("Can't write new file.");
}
...
恒等转换
对于像本教程中这样简单 Document,很容易设想输出 XML 也是简单的,但是需要考虑许多可能导致问题复杂化的因素 ―― 比如像下面这样很少出现的情况:文件的内容要受到某个 DTD 或模式的影响。通常,最好使用考虑了所有这些可能性的应用程序。
开发人员经常选择用于序列化 Document 的一种方法就是创建一个恒等转换。这是一个不包括样式表的 XSL 转换。例如:
...
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.FileOutputStream;
...
newdoc.appendChild(newRoot);
try {
DOMSource source = new DOMSource(newdoc);
StreamResult result =
new StreamResult(new FileOutputStream("processed.xml"));
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.transform(source, result);
} catch (Exception e){
e.printStackTrace();
}
}
}
这里创建了一个源和一个结果,但是由于是在使用恒等转换,因此没有创建一个对象来代表样式表。如果这是实际的转换,则可以在 Transformer 的创建过程中使用样式表。否则,Transformer 将简单地接受源(Document),然后将它发送到结果(processed.xml 文件)。
1、将文件解析为文档
三步过程
为了使用 XML 文件中的信息,必须解析文件以创建一个 Document 对象。
Document 对象是一个接口,因而不能直接将它实例化;一般情况下,应用程序会相应使用一个工厂。准确的过程因实现而异,但是基本思想是相同的。(同样,Level 3 标准化了这个任务)。在这个例子 Java 环境中,解析文件是一个三步过程:
1. 创建 DocumentBuilderFactory。DocumentBuilderFactory 对象创建 DocumentBuilder。
2. 创建 DocumentBuilder。DocumentBuilder 执行实际的解析以创建 Document 对象。
3. 解析文件以创建 Document 对象。
现在您可以开始构建应用程序了。
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(true); DocumentBuilder db = dbf.newDocumentBuilder(); doc = db.parse(docFile);
Java 的 DOM Level 2 实现允许通过以下方法控制解析器的参数:
* setCoalescing():决定解析器是否要将 CDATA 节点转换为文本,以及是否要和周围的文本节点合并(如果适用的话)。其默认值为 false。
* setExpandEntityReferences():确定是否要展开外部实体引用。如果为 true,外部数据将插入文档。其默认值为 true。(请参阅 参考资料 以了解关于使用外部实体的技巧)。
* setIgnoringComments():确定是否要忽略文件中的注释。其默认值为 false。
* setIgnoringElementContentWhitespace():确定是否要忽略元素内容中的空白(类似于浏览器对待 HTML 的方式)。其默认值为 false。
* setNamespaceAware():确定解析器是否要注意名称空间信息。其默认值为 false。
* setValidating():默认情况下,解析器不验证文档。将这个参数设置为 true 可打开验证功能。
2、获取根元素
一旦解析了文档并创建了一个 Document,应用程序就能单步调试该结构以审核、查找或显示信息。这种导航功能是将要在 Document 上执行的许多操作的基础。
对文档的单步调试首先从根元素开始。格式良好的文档仅有一个根元素,也称为 DocumentElement。应用程序首先检索这个元素。
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.File; import org.w3c.dom.Document; import org.w3c.dom.Element; public class OrderProcessor { ... System.exit(1); } //STEP 1: Get the root element Element root = doc.getDocumentElement(); System.out.println("The root element is " + root.getNodeName()); } }
3、获取节点的孩子
一旦应用程序确定了根元素,它就把根元素的孩子的列表作为一个 NodeList 来检索。NodeList 类是一系列的项,应用程序将逐个迭代这些项。 在本例中,为简洁起见,应用程序通过仅显示有多少元素出现在生成的 NodeList 中,从而获取孩子节点和验证检索结果。
import org.w3c.dom.NodeList; ... //STEP 1: Get the root element Element root = doc.getDocumentElement(); System.out.println("The root element is "+root.getNodeName()); //STEP 2: Get the children NodeList children = root.getChildNodes(); System.out.println("There are "+children.getLength() +" nodes in this document."); } }
使用 getFirstChild() 和 getNextSibling()
父子和兄弟关系提供了迭代某个节点的所有孩子的替代方法,它在某些场合下可能更为适宜,比如在这些关系和孩子的出现顺序对理解数据至关重要的时候。
在 Step 3 中,for 循环首先从根元素的第一个孩子开始。应用程序迭代第一个孩子的所有兄弟,直至已全部对它们求值。
每次应用程序执行该循环,它都要检索一个 Node 对象,输出其名称和值。注意 orders 的五个孩子包括 orders 元素和三个文本节点。还要注意元素具有一个 null 值,而不是预期的文本。包含实际内容作为其值的,是作为元素的孩子的文本节点。
for (Node child = root.getFirstChild(); child != null; child = child.getNextSibling()) { System.out.println(start.getNodeName()+" = " +start.getNodeValue()); } } }
4、编辑文档
更改节点的值
检查一下 XML 文档内容的常量是有用的,但是在处理全功能的应用程序时,您可能需要更改数据以添加、编辑、移动或删除信息。编辑数据的能力对创建新 XML 文档的过程也是至关重要的。这类更改中最简单的情况就是更改元素的文本内容。
这里的目标是更改某个元素的文本节点的值,在此例中是将每个 order 的 status 设置为 “processed”,然后向屏幕输出新的值。
使用起始节点(root)以及要更改的元素名称和要更改到的目标值作为参数,调用 changeOrder() 方法。
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,以便能够根据名称检索 price 和 qty。它是通过使用 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,它列出了所有订单不足的商品。
注意由于没有内容被添加到该元素,因此它是一个空元素。空元素没有内容,并且可以用一种特殊的简写来表示:
<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 {
删除属性
应用程序还可以删除属性。例如,在输出中显示客户信用限额信息也许是不可取的,因此应用程序可以临时地将该属性从文档中删除。
删除信息是相当简单的,只需使用 removeAttribute() 来删除数据。
Element thisOrder = (Element)orders.item(orderNum); Element customer = (Element)thisOrder.getElementsByTagName("customerid") .item(0); customer.removeAttribute("limit"); NodeList orderItems = thisOrder.getElementsByTagName("item");
5、
输出文档
准备数据
到目前为止,本教程已考察了如何接受、使用和操作 XML 数据。要完成这个周期,您还必须能够输出 XML。
对于本教程中的情况,目标输出是一个文件,该文件简单地列出每个订单、依据客户信用限额来确定的订单处理情况,以及 customerid。
<?xml version="1.0" encoding="UTF-8"?>
<processedOrders>
<order>
<status>PROCESSED</status>
<customerid>2341</customerid>
<amount>874.00</amount>
</order>
<order>
<status>REJECTED</status>
<customerid>251222</customerid>
<amount>200.00</amount>
</order>
</processedOrders>
应用程序首先创建要输出的 Document 对象。为方便起见,可以使用创建原先的 Document 的 DocumentBuilder 来创建新的 Document 对象。
...
public static void main (String args[]) {
File docFile = new File("orders.xml");
Document doc = null;
Document newdoc = null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(docFile);
newdoc = db.newDocument();
} catch (Exception e) {
System.out.print("Problem parsing the file: "+e.getMessage());
}
...
thisOrder.insertBefore(totalElement, thisOrder.getFirstChild());
}
Element newRoot = newdoc.createElement("processedOrders");
NodeList processOrders = doc.getElementsByTagName("order");
for (int orderNum = 0;
orderNum < processOrders.getLength();
orderNum++) {
Element thisOrder = (Element)processOrders.item(orderNum);
Element customerid =
(Element)thisOrder.getElementsByTagName("customerid")
.item(0);
String limit = customerid.getAttributeNode("limit").getNodeValue();
String total = thisOrder.getElementsByTagName("total").item(0)
.getFirstChild().getNodeValue();
double limitDbl = new Double(limit).doubleValue();
double totalDbl = new Double(total).doubleValue();
Element newOrder = newdoc.createElement("order");
Element newStatus = newdoc.createElement("status");
if (totalDbl > limitDbl) {
newStatus.appendChild(newdoc.createTextNode("REJECTED"));
} else {
newStatus.appendChild(newdoc.createTextNode("PROCESSED"));
}
Element newCustomer = newdoc.createElement("customerid");
String oldCustomer = customerid.getFirstChild().getNodeValue();
newCustomer.appendChild(newdoc.createTextNode(oldCustomer));
Element newTotal = newdoc.createElement("total");
newTotal.appendChild(newdoc.createTextNode(total));
newOrder.appendChild(newStatus);
newOrder.appendChild(newCustomer);
newOrder.appendChild(newTotal);
newRoot.appendChild(newOrder);
}
newdoc.appendChild(newRoot);
System.out.print(newRoot.toString());
...
在处理 orders.xml 之后,应用程序创建了一个新的元素 processedOrders,这个新的元素最终将成为新文档的根元素。然后它遍历每个订单。对于每个订单,它都提取其 total 和 limit 信息。
接下来,应用程序为订单创建新元素:order、status、customerid 和 amount。它根据汇总款项是否超过客户的信用限额来填充 status,然后相应地填充其他元素。
一旦应用程序为订单创建了元素,它就必须将这些元素整合起来。它首先向新的 order 元素添加状态、客户信息和汇总款项。然后它把新的 order 添加到 newRoot 元素。
尽管如此,newRoot 元素并没有实际连接到某个父节点。当应用程序完成所有订单的处理时,newRoot 就被追加到新的文档。
最后,应用程序将 newRoot 转换为一个 String,并简单地将它发送到 System.out,从而输出数据。
标准化文档
注意:在节点上,一些版本的 Java 代码不支持这个版本的 toString()。如果出现这种情况,使用 恒等转换 中展示的技巧就可以查看节点的内容。
创建 XML 文件
现在应用程序已经创建了新的信息,将这个信息输出到某个文件是很简单的。
对数据也使用了相同的逻辑,只不过应用程序不是将它输出到屏幕,而是将它输出到一个文件。
要注意的一件重要事情是,由于 XML 数据是文本,因此可以通过任何方式来对它进行格式化。例如,您可以创建 stepThroughAll() 的变体,它将创建缩进的或完美输出的版本。记住,这将创建额外的空白(文本)节点。
...
import java.io.FileWriter;
...
try
{
File newFile = new File("processedOrders.xml");
FileWriter newFileStream = new FileWriter(newFile);
newFileStream.write ("<?xml version=\"1.0\"?>");
newFileStream.write ("<!DOCTYPE
"+doc.getDoctype().getName()+" ");
if (doc.getDoctype().getSystemId() != null) {
newFileStream.write (" SYSTEM ");
newFileStream.write (doc.getDoctype().getSystemId());
}
if (doc.getDoctype().getPublicId() != null) {
newFileStream.write (" PUBLIC ");
newFileStream.write (doc.getDoctype().getPublicId());
}
newFileStream.write (">");
newFileStream.write (newRoot.toString());
newFileStream.close();
} catch (IOException e) {
System.out.println("Can't write new file.");
}
...
恒等转换
对于像本教程中这样简单 Document,很容易设想输出 XML 也是简单的,但是需要考虑许多可能导致问题复杂化的因素 ―― 比如像下面这样很少出现的情况:文件的内容要受到某个 DTD 或模式的影响。通常,最好使用考虑了所有这些可能性的应用程序。
开发人员经常选择用于序列化 Document 的一种方法就是创建一个恒等转换。这是一个不包括样式表的 XSL 转换。例如:
...
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.FileOutputStream;
...
newdoc.appendChild(newRoot);
try {
DOMSource source = new DOMSource(newdoc);
StreamResult result =
new StreamResult(new FileOutputStream("processed.xml"));
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.transform(source, result);
} catch (Exception e){
e.printStackTrace();
}
}
}
这里创建了一个源和一个结果,但是由于是在使用恒等转换,因此没有创建一个对象来代表样式表。如果这是实际的转换,则可以在 Transformer 的创建过程中使用样式表。否则,Transformer 将简单地接受源(Document),然后将它发送到结果(processed.xml 文件)。
相关推荐
"前端学习笔记-黑马程序员JS" ...这篇前端学习笔记涵盖了 JavaScript 的基础知识,包括变量、数据类型、运算符、流程控制、数组、函数、对象、内置对象和 Web APIs 等知识点,为学习 JavaScript 提供了系统的指导。
**jQuery学习笔记--1** jQuery是一个轻量级的JavaScript库,它极大地简化了JavaScript的DOM操作、事件处理、动画设计以及Ajax交互。本篇笔记将深入探讨jQuery的基础知识,包括其核心概念、选择器、DOM操作、事件...
这篇学习笔记将带你探索JavaScript的核心概念,包括变量、数据类型、控制流、函数、对象和类等,这些都是构建复杂应用程序的基础。 首先,我们要了解JavaScript的基础语法。在JavaScript中,变量是存储数据的容器,...
标题“13-文本小节-dom转vdom.md”所涉及的知识点是关于如何将DOM结构转换为虚拟DOM(vDOM)。vDOM是现代前端框架(如React)中的重要概念,它能够提升Web应用性能和开发效率。以下是从描述和部分具体内容中提炼出的...
### JSP 学习笔记概览 #### 为什么选择 JSP? 1. **动态效果**:JSP 允许在服务器端执行动态脚本,生成动态网页内容。 2. **状态管理**:能够处理客户端的状态信息,实现会话管理和用户认证等功能。 3. **重用性**...
本学习笔记专为初学者设计,旨在帮助新接触JavaScript的人快速掌握这门语言的核心概念和实用技巧。 首先,"JavaScript特效.chm"可能是一份关于JavaScript实现的各种网页特效的教程。这些特效可能包括图片轮播、下拉...
根据给定的文件信息,我们可以总结出一系列与DOM(Document Object Model)操作相关的知识点,主要集中在HTML元素的选择、样式修改以及动态元素创建等方面。以下是详细的知识点解析: ### 一、选择并修改DOM元素 #...
### Vue项目总结和前端学习笔记知识点梳理 #### Vue环境搭建 在学习Vue之前,首先要配置好开发环境。这包括安装Node.js和npm(Node.js的包管理器)。Node.js可以通过访问官方下载页面,选择对应操作系统的.msi格式...
**标题解析:** "Dom4j学习笔记" 这个标题明确指出了我们要探讨的主题——Dom4j。Dom4j是一个流行的Java库,用于处理XML文档。它提供了丰富的API,使得XML的读取、写入、操作变得简单易行。在学习笔记中,通常会涵盖...
根据给定的文件信息,我们可以总结出以下关于DOM(Document Object Model)操作的关键知识点: ### DOM简介 DOM是一种处理HTML和XML文档的标准接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。DOM...
在JS基本功DOM学习笔记中,我们将深入探讨以下几个核心知识点: 1. **DOM树**:DOM将网页内容表示为一棵由节点构成的树形结构,其中每个节点代表HTML元素、属性、文本等。根节点通常是`document`,其他节点如`<div>...
DOM4J的学习笔记主要涵盖以下几个核心知识点: 1. **DOM4J概述**: DOM4J是一个开源项目,其设计目标是提供一个简单且功能丰富的XML API,它既支持SAX和DOM,又引入了面向对象的设计,使得XML处理更加方便。DOM4J...
这份“javascript学习笔记整理知识点整理”是针对初学者的一份宝贵资料,涵盖了JavaScript的基础知识,旨在帮助新手快速入门并掌握这门语言的核心概念。 一、变量与数据类型 在JavaScript中,变量用于存储数据。...
Python学习笔记5的知识点包括: 1. datetime模块的使用:datetime是Python处理日期和时间的标准库,可以完成多种与日期和时间相关的工作。 - 获取当前日期和时间:使用datetime.now()函数可以获取当前的日期和...
标题"Dom4j学习教程+API+xml实用大全+xml学习笔记+htc"提及了几个关键主题,包括Dom4j的学习资源、API文档,以及关于XML的实用指南和学习笔记,还提到了一个名为"htc"的文件,可能是关于HTC设备或技术的文档。...
以上是JavaScript学习笔记中提到的一些核心知识点,通过对这些知识点的理解和熟练应用,可以为进一步学习和掌握JavaScript打下坚实的基础。在实际开发过程中,结合具体的项目需求,这些知识会得到更深入的拓展和应用...
根据给定文件的信息,我们可以提炼出以下IT领域的关键知识点,主要围绕DOM操作、JavaScript事件处理以及数据剪贴板管理: ### 1. DOM标题滚动效果实现 在第一个代码示例中,通过`document.title`属性与字符串操作...
### DOM Canvas 绘图知识点详解 #### 一、Canvas 基础介绍 ...Canvas 元素本身并不...以上是关于 DOM Canvas 绘图的基础知识点,涵盖了从获取 Canvas 元素到具体绘图命令的详细解释,希望对学习 Canvas 绘图有所帮助。
根据给定的文件信息,我们可以总结出一系列与DOM(Document Object Model)操作、JavaScript事件处理以及浏览器窗口操作相关的IT知识点。以下是对这些知识点的详细解释: ### 1. DOM Event Handling(DOM事件处理)...