在 XML 文件的特定位置插入字符串
insert a string in a particular position in an XML file
我有一个 XML 文件 (client_23.xml)
,如下所示。我有一个字符串变量 out
,我需要在 XML 下面插入一个特定的位置。这不是我的完整 XML,因为我还有很多其他嵌套的东西,功能标签将在其中并且它不一致,因为这个 XML 是通过代码生成的,所以我需要
<?xml version="1.0"?>
<clients>
<!-- some other code here -->
<function>
</function>
<function>
</function>
<function>
<name>data_values</name>
<variables>
<variable>
<name>temp</name>
<type>double</type>
</variable>
</variables>
<block>
<opster>temp = 1</opster>
</block>
</function>
</clients>
我需要解析上面的XML,找到一个名为data_values
的函数,然后在<block>
标签中插入out
字符串变量。这不是我的完整 XML,因为我有很多其他嵌套的东西,函数标签将在其中,并且它不一致,因为这个 XML 是通过代码生成的,所以我需要解析和迭代,并且找到了再放。
所以最终 xml 将如下所示:
<?xml version="1.0"?>
<clients>
<!-- some other code here -->
<function>
</function>
<function>
</function>
<function>
<name>data_values</name>
<variables>
<variable>
<name>temp</name>
<type>double</type>
</variable>
</variables>
<block>
<!-- new stuff added and old things were gone -->
<opster>hello = world</opster>
<opster>abc = def</opster>
</block>
</function>
</clients>
下面是我得到的代码,但我无法理解如何在块标记中的 data_values
函数中放入变量。
StringBuilder out = new StringBuilder();
// some data in out variable, properly formatted with new lines.
String location = key.getPathName();
String clientIdPath = location + "/" + "client_23.xml";
File fileName = new File(clientIdPath);
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(fileName);
NodeList dataValueFunction = document.getElementsByTagName("function");
// I have started iterating but I am not able to understand how to insert "out"
// variable inside block
for (int i = 0; i < dataValueFunction.getLength(); i++) {
Node node = dataValueFunction.item(i);
System.out.println(node.getNodeName());
NodeList childList = node.getChildNodes();
for (int j = 0; j < childList.getLength(); j++) {
Node node1 = childList.item(j);
if (node1 != null && node1.getNodeName().equalsIgnoreCase("name")
&& node1.getTextContent().equalsIgnoreCase("data_values")) {
// now what should I do here?
}
}
}
检查这个问题。您可以使用 XPath 表达式找到正确的函数标签并使用 Xpath 更新它。
How to update XML using XPath and Java
这是一个快速代码。
public static void main(String[] args) {
try {
FileInputStream file = new FileInputStream(new File("data.xml"));
List<String> outs = Arrays.asList(new String[] { "hello = world", "abc = def" });
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
System.out.println("*************************");
String expression = "//clients/function/name[text()='data_values']";
System.out.println(expression);
Node nameTag = (Node) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODE);
for (int i = 0; i < nameTag.getParentNode().getChildNodes().getLength(); i++) {
if (nameTag.getParentNode().getChildNodes().item(i).getNodeName().equals("block")) {
System.out.println("GOT BLOCK");
nameTag.getParentNode().removeChild(nameTag.getParentNode().getChildNodes().item(i));
Node node = xmlDocument.createElement("block");
nameTag.getParentNode().appendChild(node);
for (String out : outs) {
Node newNode = xmlDocument.createElement("opster");
newNode.setTextContent(out);
node.appendChild(newNode);
}
}
}
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
DOMSource source = new DOMSource(xmlDocument);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
已编辑:将 "out" 的值添加到先前存在的 "block" 元素
根据@user489732 的建议,使用 XPath 定位节点,然后使用您的值创建一个新节点,然后将其插入到函数元素中。不过,我会使用不同的方法:
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException, TransformerException {
// Your initial input
String myXML = "<?xml version=\"1.0\"?>\n" +
"<clients>\n" +
" <!-- some other code here -->\n" +
"\n" +
" <function>\n" +
" </function>\n" +
"\n" +
" <function>\n" +
" </function>\n" +
"\n" +
" <function>\n" +
" <name>data_values</name>\n" +
" <variables>\n" +
" <variable>\n" +
" <name>temp</name>\n" +
" <type>double</type>\n" +
" </variable>\n" +
" </variables>\n" +
" <block>\n" +
" <!-- new stuff added and old things were gone -->\n" +
" <opster>hello = world</opster>\n" +
" <opster>abc = def</opster>\n" +
" </block>\n" +
" </function>\n" +
"</clients>";
// you will have to create an input stream from your XML file,
// in this case I'm using a ByteArrayInputStream, you'll probably
// need a FileInputStream
InputStream myXMLStream = new ByteArrayInputStream(myXML.getBytes(Charset.forName("UTF-8")));
String out = "My value whatever it is";
// Create xpath expression
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("/clients/function/block[../name/text() = 'data_values']");
// Load document
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(myXMLStream);
// Search for the node
NodeList blockList = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
Element blockElement = (Element)blockList.item(0);
// Insert your value inside element "block"
// CAVEAT: if the value of "out" contains "tags" (xml elements)
// then "createTextNode" won't work, you need to create elements
// with the different methods of "document" (document.createXXXX())
Node textNode = document.createTextNode(out);
blockElement.insertBefore(textNode, blockElement.getFirstChild());
// Write the document to its final destination
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(document);
// instead of System.out, use a more appropriate stream:
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
}
如果有人认为到目前为止提供的答案太复杂,这里是另一个,它与 vtd-xml... here is why vtd-xml is much better than DOM
import com.ximpleware.*;
public class replaceContent {
public static void main(String[] s) throws VTDException, Exception{
VTDGen vg = new VTDGen();
AutoPilot ap = new AutoPilot();
XMLModifier xm = new XMLModifier();
if (vg.parseFile("d:\xml\input2.xml", true)){
VTDNav vn = vg.getNav();
ap.bind(vn);
xm.bind(vn);
ap.selectXPath("/clients/function/block");
int i=-1;
byte[] s1 = ("\r\n\t\t<opster>hello = world</opster>\r\n\t\t"+
"<opster>abc = def</opster>\r\n\t").getBytes();
while((i=ap.evalXPath())!=-1){
xm.insertAfterHead(s1);
long l= vn.getContentFragment(); // add new stuff after the starting tag
xm.removeContent((int)l, (int)(l>>32)); // remove old stuff
}
xm.output("d:\xml\new.xml");
}
}
}
我有一个 XML 文件 (client_23.xml)
,如下所示。我有一个字符串变量 out
,我需要在 XML 下面插入一个特定的位置。这不是我的完整 XML,因为我还有很多其他嵌套的东西,功能标签将在其中并且它不一致,因为这个 XML 是通过代码生成的,所以我需要
<?xml version="1.0"?>
<clients>
<!-- some other code here -->
<function>
</function>
<function>
</function>
<function>
<name>data_values</name>
<variables>
<variable>
<name>temp</name>
<type>double</type>
</variable>
</variables>
<block>
<opster>temp = 1</opster>
</block>
</function>
</clients>
我需要解析上面的XML,找到一个名为data_values
的函数,然后在<block>
标签中插入out
字符串变量。这不是我的完整 XML,因为我有很多其他嵌套的东西,函数标签将在其中,并且它不一致,因为这个 XML 是通过代码生成的,所以我需要解析和迭代,并且找到了再放。
所以最终 xml 将如下所示:
<?xml version="1.0"?>
<clients>
<!-- some other code here -->
<function>
</function>
<function>
</function>
<function>
<name>data_values</name>
<variables>
<variable>
<name>temp</name>
<type>double</type>
</variable>
</variables>
<block>
<!-- new stuff added and old things were gone -->
<opster>hello = world</opster>
<opster>abc = def</opster>
</block>
</function>
</clients>
下面是我得到的代码,但我无法理解如何在块标记中的 data_values
函数中放入变量。
StringBuilder out = new StringBuilder();
// some data in out variable, properly formatted with new lines.
String location = key.getPathName();
String clientIdPath = location + "/" + "client_23.xml";
File fileName = new File(clientIdPath);
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(fileName);
NodeList dataValueFunction = document.getElementsByTagName("function");
// I have started iterating but I am not able to understand how to insert "out"
// variable inside block
for (int i = 0; i < dataValueFunction.getLength(); i++) {
Node node = dataValueFunction.item(i);
System.out.println(node.getNodeName());
NodeList childList = node.getChildNodes();
for (int j = 0; j < childList.getLength(); j++) {
Node node1 = childList.item(j);
if (node1 != null && node1.getNodeName().equalsIgnoreCase("name")
&& node1.getTextContent().equalsIgnoreCase("data_values")) {
// now what should I do here?
}
}
}
检查这个问题。您可以使用 XPath 表达式找到正确的函数标签并使用 Xpath 更新它。
How to update XML using XPath and Java
这是一个快速代码。
public static void main(String[] args) {
try {
FileInputStream file = new FileInputStream(new File("data.xml"));
List<String> outs = Arrays.asList(new String[] { "hello = world", "abc = def" });
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
System.out.println("*************************");
String expression = "//clients/function/name[text()='data_values']";
System.out.println(expression);
Node nameTag = (Node) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODE);
for (int i = 0; i < nameTag.getParentNode().getChildNodes().getLength(); i++) {
if (nameTag.getParentNode().getChildNodes().item(i).getNodeName().equals("block")) {
System.out.println("GOT BLOCK");
nameTag.getParentNode().removeChild(nameTag.getParentNode().getChildNodes().item(i));
Node node = xmlDocument.createElement("block");
nameTag.getParentNode().appendChild(node);
for (String out : outs) {
Node newNode = xmlDocument.createElement("opster");
newNode.setTextContent(out);
node.appendChild(newNode);
}
}
}
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
DOMSource source = new DOMSource(xmlDocument);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
已编辑:将 "out" 的值添加到先前存在的 "block" 元素
根据@user489732 的建议,使用 XPath 定位节点,然后使用您的值创建一个新节点,然后将其插入到函数元素中。不过,我会使用不同的方法:
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException, TransformerException {
// Your initial input
String myXML = "<?xml version=\"1.0\"?>\n" +
"<clients>\n" +
" <!-- some other code here -->\n" +
"\n" +
" <function>\n" +
" </function>\n" +
"\n" +
" <function>\n" +
" </function>\n" +
"\n" +
" <function>\n" +
" <name>data_values</name>\n" +
" <variables>\n" +
" <variable>\n" +
" <name>temp</name>\n" +
" <type>double</type>\n" +
" </variable>\n" +
" </variables>\n" +
" <block>\n" +
" <!-- new stuff added and old things were gone -->\n" +
" <opster>hello = world</opster>\n" +
" <opster>abc = def</opster>\n" +
" </block>\n" +
" </function>\n" +
"</clients>";
// you will have to create an input stream from your XML file,
// in this case I'm using a ByteArrayInputStream, you'll probably
// need a FileInputStream
InputStream myXMLStream = new ByteArrayInputStream(myXML.getBytes(Charset.forName("UTF-8")));
String out = "My value whatever it is";
// Create xpath expression
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("/clients/function/block[../name/text() = 'data_values']");
// Load document
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(myXMLStream);
// Search for the node
NodeList blockList = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
Element blockElement = (Element)blockList.item(0);
// Insert your value inside element "block"
// CAVEAT: if the value of "out" contains "tags" (xml elements)
// then "createTextNode" won't work, you need to create elements
// with the different methods of "document" (document.createXXXX())
Node textNode = document.createTextNode(out);
blockElement.insertBefore(textNode, blockElement.getFirstChild());
// Write the document to its final destination
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(document);
// instead of System.out, use a more appropriate stream:
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
}
如果有人认为到目前为止提供的答案太复杂,这里是另一个,它与 vtd-xml... here is why vtd-xml is much better than DOM
import com.ximpleware.*;
public class replaceContent {
public static void main(String[] s) throws VTDException, Exception{
VTDGen vg = new VTDGen();
AutoPilot ap = new AutoPilot();
XMLModifier xm = new XMLModifier();
if (vg.parseFile("d:\xml\input2.xml", true)){
VTDNav vn = vg.getNav();
ap.bind(vn);
xm.bind(vn);
ap.selectXPath("/clients/function/block");
int i=-1;
byte[] s1 = ("\r\n\t\t<opster>hello = world</opster>\r\n\t\t"+
"<opster>abc = def</opster>\r\n\t").getBytes();
while((i=ap.evalXPath())!=-1){
xm.insertAfterHead(s1);
long l= vn.getContentFragment(); // add new stuff after the starting tag
xm.removeContent((int)l, (int)(l>>32)); // remove old stuff
}
xm.output("d:\xml\new.xml");
}
}
}