Java学习之Xml系列三:dtd校验、改、增、删
见摘要、见代码注释,其他话不多说:
DTD文档:
<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT SwordLibrary (Sword*)> <!ELEMENT Sword (SwordName,Price,Attack)> <!ELEMENT SwordName (#PCDATA)> <!ELEMENT Price (#PCDATA)> <!ELEMENT Attack (#PCDATA)> <!ATTLIST Sword sno CDATA #REQUIRED> <!ATTLIST Price type CDATA #IMPLIED> <!ATTLIST Attack factor CDATA "1.0">
Xml文档:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE SwordLibrary SYSTEM "SwordTypeDefinition.dtd"> <SwordLibrary> <Sword sno="s1"> <SwordName>欢欣之刃</SwordName> <Price>1000</Price> <Attack factor="1.0">10</Attack> </Sword> <Sword sno="s2"> <SwordName>夜叉</SwordName> <Price>2050</Price> <Attack factor="2.0">30</Attack> </Sword> <Sword sno="s3"> <SwordName>魔棒</SwordName> <Price type="Dollar">200</Price> <Attack factor="1.0">0</Attack> </Sword> </SwordLibrary>
java代码:
package JavaLeaner.XmlTest; import java.io.FileOutputStream; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class XmlDemo3 { /* * 强制执行dtd校验,但是是在运行时 * */ @Test public void Test1() throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //强制执行dtd校验,但是是在运行时 factory.setValidating(true); DocumentBuilder docDuilder = factory.newDocumentBuilder(); Document doc = docDuilder.parse("src/JavaLeaner/XmlTest/SwordLib.xml"); /* * 使用DocumentBuilderFactory的setValidating(true)方法可以将dtd校验在运行阶段执行 * 可以正常编译,但在会爬出异常:(异常被声明,所以JUnit的运行条颜色是绿色) * Warning: validation was turned on but an org.xml.sax.ErrorHandler was not set, which is probably not what is desired. Parser will use a default ErrorHandler to print the first 10 errors. Please call the ‘setErrorHandler‘ method to fix this. Error: URI=file:///home/XXXX/workspace/Learning/HelloWorld/src/JavaLeaner/XmlTest/SwordLib.xml Line=9: 需要属性 "sno", 并且必须为元素类型 "Sword" 指定该属性。 */ //单步执行抛出异常的语句在docDuilder.parse } /* * 改: * 修改修改已有标签内容和属性 * 注意:属性如果有则是修改,无则会添加,使用的都是setAttribute */ @Test public void Test2() throws ParserConfigurationException, SAXException, IOException, TransformerException { String fileName="src/JavaLeaner/XmlTest/SwordLib.xml"; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //factory.setValidating(true); DocumentBuilder docDuilder = factory.newDocumentBuilder(); Document doc = docDuilder.parse(fileName); //Element rootElement = doc.getDocumentElement(); Element rootElement = (Element)doc.getElementsByTagName("SwordLibrary").item(0); NodeList list= rootElement.getElementsByTagName("Price");//由此可以看出,这里的搜索不仅仅是子元素,也可以是孙子元素 for(int i=0;i<list.getLength();i++) { Element e = (Element)list.item(i); //更改或者添加属性设置 e.setAttribute("type", "yan"); //更改元素内容 e.setTextContent("0"); } //将更改后的文档对象写回xml文件 TransformerFactory transformerfactory = TransformerFactory.newInstance(); Transformer tf=transformerfactory.newTransformer(); //tf.transform(new DOMSource(doc.getDoctype()),new StreamResult(new FileOutputStream(fileName))); //注意:如果想让xml中的Doctype标签不丢失,必须在转换类对象进行输出属性设置。 //下面这句由于对xml的Dctype设置的dtd声明为public的情况 //tf.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_PUBLIC, doc.getDoctype().getPublicId()); //下面这句由于对xml的Dctype设置的dtd声明为System的情况 tf.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId()); tf.transform(new DOMSource(doc),new StreamResult(new FileOutputStream(fileName))); /* <?xml version="1.0" encoding="UTF-8" standalone="no"?><SwordLibrary> <Sword sno="s1"> <SwordName>欢欣之刃</SwordName> <Price type="yan">0</Price> <Attack factor="1.0">10</Attack> </Sword> <Sword sno="s2"> <SwordName>夜叉</SwordName> <Price type="yan">0</Price> <Attack factor="2.0">30</Attack> </Sword> <Sword sno="s3"> <SwordName>魔棒</SwordName> <Price type="yan">0</Price> <Attack factor="1.0">0</Attack> </Sword> </SwordLibrary> */ } /* * * 追加节点 * */ @Test public void Test3() throws ParserConfigurationException, SAXException, IOException, TransformerException { String fileName="src/JavaLeaner/XmlTest/SwordLib.xml"; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); DocumentBuilder docDuilder = factory.newDocumentBuilder(); Document doc = docDuilder.parse(fileName); //用文档对象创建元素 Element eSword=doc.createElement("Sword"); eSword.setAttribute("sno", "s4"); //用文档对象创建子元素 Element esname=doc.createElement("SwordName"); Element esprice=doc.createElement("Price"); Element esattack=doc.createElement("Attack"); //发现问题后,补上的 esname.setTextContent("散华"); esprice.setTextContent("2050"); esattack.setTextContent("30"); //将子元素添加到元素里 eSword.appendChild(esname); eSword.appendChild(esprice); eSword.appendChild(esattack); //将元素添加到文档里,及根元素 doc.getDocumentElement().appendChild(eSword); //注意: doc.appendChild(eSword);是错误的 //eSword应该在根元素SwordLibrary下 System.out.println("doc.getDocumentElement(): "+doc.getDocumentElement().getNodeName()); //将更改后的文档对象写回xml文件 TransformerFactory transformerfactory = TransformerFactory.newInstance(); Transformer tf=transformerfactory.newTransformer(); //注意:如果想让xml中的Doctype标签不丢失,必须在转换类对象进行输出属性设置。 //下面这句由于对xml的Dctype设置的dtd声明为public的情况 //tf.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_PUBLIC, doc.getDoctype().getPublicId()); //下面这句由于对xml的Dctype设置的dtd声明为System的情况 tf.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId()); tf.transform(new DOMSource(doc),new StreamResult(new FileOutputStream(fileName))); /* * * * * Warning: validation was turned on but an org.xml.sax.ErrorHandler was * not set, which is probably not what is desired. Parser will use a * default ErrorHandler to print the first 10 errors. Please call the * ‘setErrorHandler‘ method to fix this. Error: * URI=file:///home/neil/workspace * /Learning/HelloWorld/src/JavaLeaner/XmlTest/SwordLib.xml Line=1: * 文档根元素 "SwordLibrary" 必须匹配 DOCTYPE 根 "null"。 Error: * URI=file:///home/neil * /workspace/Learning/HelloWorld/src/JavaLeaner/XmlTest/SwordLib.xml * Line=1: 文档无效: 找不到语法。 doc.getDocumentElement(): SwordLibrary * * * <?xml version="1.0" encoding="UTF-8" standalone="no"?><SwordLibrary> * <Sword sno="s1"> <SwordName>欢欣之刃</SwordName> <Price>1000</Price> * <Attack factor="1.0">10</Attack> </Sword> <Sword sno="s2"> * <SwordName>夜叉</SwordName> <Price>2050</Price> <Attack * factor="2.0">30</Attack> </Sword> <Sword sno="s3"> * <SwordName>魔棒</SwordName> <Price type="Dollar">200</Price> <Attack * factor="1.0">0</Attack> </Sword> <Sword * sno="s4"><SwordName/><Price/><Attack/></Sword></SwordLibrary> */ } /* * 实验 * 在之前的实验中发现,虽然xml被成功更改,但是Doctype属性在文档对象写回文件后发生了丢失的现象 * 这是因为DocType写回xml文件时,需要单独设置属性setOutputProperty */ @Test public void Test4() throws ParserConfigurationException, SAXException, IOException, TransformerException { { String fileName="src/JavaLeaner/XmlTest/SwordLib.xml"; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //factory.setValidating(true); DocumentBuilder docDuilder = factory.newDocumentBuilder(); Document doc = docDuilder.parse(fileName); /* DocumentType doctype = doc.getDoctype(); String docText = doctype.getName(); System.out.println("DocumentType:" + docText);*/ TransformerFactory transformerfactory = TransformerFactory.newInstance(); Transformer tf=transformerfactory.newTransformer(); if(doc==null) { System.out.println("doc is null"); return; } if(doc.getDoctype()==null) { System.out.println("DocumentType is null"); return; } //注意:如果想让xml中的Doctype标签不丢失,必须在转换类对象进行输出属性设置。 //下面这句由于对xml的Dctype设置的dtd声明为public的情况 //tf.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_PUBLIC, doc.getDoctype().getPublicId()); //下面这句由于对xml的Dctype设置的dtd声明为System的情况 tf.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId()); //doc.setXmlStandalone(xmlStandalone); DOMSource domSource=new DOMSource(doc); tf.transform(domSource,new StreamResult(new FileOutputStream(fileName))); /* DocumentType doctype2 = doc.getDoctype(); if (doctype2 != null) { String docText2 = doctype2.getName(); System.out.println("DocumentType:" + docText2); } else { System.out.println("DocumentType is null"); }*/ } { String fileName="src/JavaLeaner/XmlTest/SwordLib.xml"; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //factory.setValidating(true); DocumentBuilder docDuilder = factory.newDocumentBuilder(); Document doc = docDuilder.parse(fileName); System.out.println("getXmlStandalone:" + (doc.getXmlStandalone()?1:0)); DocumentType doctype = doc.getDoctype(); if (doctype != null) { String docText = doctype.getName(); System.out.println("DocumentType:" + docText); } else { System.out.println("DocumentType is null"); } } } /* * 删除节点:方法1://从爸爸找起,逐一审查儿子 */ @Test public void Test5() throws ParserConfigurationException, SAXException, IOException, TransformerException { String fileName="src/JavaLeaner/XmlTest/SwordLib.xml"; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); DocumentBuilder docDuilder = factory.newDocumentBuilder(); Document doc = docDuilder.parse(fileName); //从爸爸找起,逐一审查儿子 NodeList list = doc.getElementsByTagName("Sword"); for (int i = 0; i < list.getLength(); i++) { Element eSword = (Element) list.item(i); if (eSword.getElementsByTagName("SwordName").getLength() >= 0) { Element ename = (Element) eSword.getElementsByTagName( "SwordName").item(0); if ("散华".equals(ename.getTextContent())) { ((Element)doc.getDocumentElement()).removeChild(eSword); System.out.println("deleted!"); } } } //将更改后的文档对象写回xml文件 TransformerFactory transformerfactory = TransformerFactory.newInstance(); Transformer tf=transformerfactory.newTransformer(); //如果想让xml中的Doctype标签不丢失,必须在转换类对象进行输出属性设置。 tf.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId()); tf.transform(new DOMSource(doc),new StreamResult(new FileOutputStream(fileName))); } /* * 删除节点:方法2://直接找当事人,然后爷爷打爸爸。(看不懂吗?看看代码就知道了) */ @Test public void Test6() throws ParserConfigurationException, SAXException, IOException, TransformerException { String fileName="src/JavaLeaner/XmlTest/SwordLib.xml"; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); DocumentBuilder docDuilder = factory.newDocumentBuilder(); Document doc = docDuilder.parse(fileName); NodeList list = doc.getElementsByTagName("SwordName"); for (int i = 0; i < list.getLength(); i++) { Element ename = (Element) list.item(i); if("散华".equals(ename.getTextContent())) { //典型的爷爷打爸爸 ename.getParentNode().getParentNode().removeChild(ename.getParentNode()); System.out.println("deleted!"); } } //将更改后的文档对象写回xml文件 TransformerFactory transformerfactory = TransformerFactory.newInstance(); Transformer tf=transformerfactory.newTransformer(); //如果想让xml中的Doctype标签不丢失,必须在转换类对象进行输出属性设置。 tf.setOutputProperty(javax.xml.transform.OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId()); tf.transform(new DOMSource(doc),new StreamResult(new FileOutputStream(fileName))); } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。