【问题标题】:insert a string in a particular position in an XML file在 XML 文件的特定位置插入字符串
【发布时间】:2015-09-17 22:59:50
【问题描述】:

我有一个 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的函数,然后在&lt;block&gt;标签中插入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?
        }
    }
}

【问题讨论】:

    标签: java xml parsing dom sax


    【解决方案1】:

    检查这个问题。您可以使用 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();
        }
    }
    

    【讨论】:

    • 对于 Xpath,我们需要在正确的位置有正确的 XML 标签名称。在我的例子中,XML 标签可以上下浮动。我在考虑迭代然后找到它然后放。
    • 使用 Xpath,您可以找到带有特定文本的标签。我认为这就是你想要做的。检查此链接stackoverflow.com/questions/1982624/…
    • 嗯,我对 Xpath 不太熟悉。你能为我的用例提供一个例子,然后我可以试试看它是否有效?
    • 你期望的函数标签结果是什么?
    • 嗯,这是我不知道的,因为它是由代码生成的,所以我们可以有多个嵌套的东西,这就是 Xpath 可能无法工作的原因。
    【解决方案2】:

    已编辑:将“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);
    }
    

    【讨论】:

      【解决方案3】:

      如果有人认为目前提供的答案太复杂,这里还有一个,vtd-xml...这里是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");
              }
              }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-01-20
        • 2012-12-01
        • 2021-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多