我想获取一个XML文件并替换元素的值.例如,如果我的XML文件如下所示:
<abc>
<xyz>original</xyz>
</abc>
Run Code Online (Sandbox Code Playgroud)
我想用另一个字符串替换xyz元素的原始值,无论它是什么,以便生成的文件如下所示:
<abc>
<xyz>replacement</xyz>
</abc>
Run Code Online (Sandbox Code Playgroud)
你会怎么做?我知道我可以编写一个Java程序来执行此操作,但我认为替换单个元素的值太过分了,并且可以使用sed使用正则表达式进行替换.然而,我对这个命令不太新手,我希望有一种灵魂阅读,这将能够为我提供正确的正则表达式.
一个想法是做这样的事情:
sed s/\<xyz\>.*\<\\xyz\>/\<xyz\>replacement\<\\xyz\>/ <original.xml >new.xml
Run Code Online (Sandbox Code Playgroud)
也许我最好用我想要的替换文件的整行,因为我会知道我想要使用的元素名称和新值?但是这假设所讨论的元素在一行上,并且没有其他XML数据在同一行上.我宁愿有一个命令,它基本上会用我指定的新字符串替换元素xyz的值,而不必担心元素是否全部在一行上,等等.
如果sed不是这项工作的最佳工具,那么请给我一个更好的方法.
如果有人能引导我朝着正确的方向前进,我会非常感激,你可能会节省我数小时的试验和错误.提前致谢!
- 詹姆士
sed不会是一个简单的工具,用于多线替换.可以使用它的N命令和一些递归来实现它们,如果已经找到了标签的关闭,则在每行读取后进行检查......但它并不漂亮,你永远不会记住它.
当然,实际解析xml和替换标签将是最安全的事情,但如果你知道你不会遇到任何问题,你可以试试这个:
perl -p -0777 -e 's@<xyz>.*?</xyz>@<xyz>new-value</xyz>@sg' <xml-file>
Run Code Online (Sandbox Code Playgroud)
打破这个:
-p 告诉它循环输入并打印-0777 告诉它使用文件的结尾作为输入分隔符,以便它在一个啜食中得到整个事物-e 这意味着我希望你做的事情替换本身:
@作为分隔符,这样你就不必逃避/*?,非贪婪的版本,尽可能少匹配,所以我们不会一直到</xyz>文件的最后一次出现s修饰符来.匹配换行符(以获取多行标记值)g修饰符多次匹配模式田田!这会将结果打印到stdout - 一旦您确认它符合您的要求,添加-i选项以告诉它编辑文件.
好吧,所以我硬着头皮花时间编写了一个 Java 程序来完成我想要的任务。下面是我的 main() 方法调用的操作方法,该方法完成工作,以防将来对其他人有帮助:
/**
* Takes an input XML file, replaces the text value of the node specified by an XPath parameter, and writes a new
* XML file with the updated data.
*
* @param inputXmlFilePathName
* @param outputXmlFilePathName
* @param elementXpath
* @param elementValue
* @param replaceAllFoundElements
*/
public static void replaceElementValue(final String inputXmlFilePathName,
final String outputXmlFilePathName,
final String elementXpathExpression,
final String elementValue,
final boolean replaceAllFoundElements)
{
try
{
// get the template XML as a W3C Document Object Model which we can later write back as a file
InputSource inputSource = new InputSource(new FileInputStream(inputXmlFilePathName));
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
Document document = documentBuilderFactory.newDocumentBuilder().parse(inputSource);
// create an XPath expression to access the element's node
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
XPathExpression xpathExpression = xpath.compile(elementXpathExpression);
// get the node(s) which corresponds to the XPath expression and replace the value
Object xpathExpressionResult = xpathExpression.evaluate(document, XPathConstants.NODESET);
if (xpathExpressionResult == null)
{
throw new RuntimeException("Failed to find a node corresponding to the provided XPath.");
}
NodeList nodeList = (NodeList) xpathExpressionResult;
if ((nodeList.getLength() > 1) && !replaceAllFoundElements)
{
throw new RuntimeException("Found multiple nodes corresponding to the provided XPath and multiple replacements not specified.");
}
for (int i = 0; i < nodeList.getLength(); i++)
{
nodeList.item(i).setTextContent(elementValue);
}
// prepare the DOM document for writing
Source source = new DOMSource(document);
// prepare the output file
File file = new File(outputXmlFilePathName);
Result result = new StreamResult(file);
// write the DOM document to the file
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(source, result);
}
catch (Exception ex)
{
throw new RuntimeException("Failed to replace the element value.", ex);
}
}
Run Code Online (Sandbox Code Playgroud)
我像这样运行程序:
$ java -cp xmlutility.jar com.abc.util.XmlUtility input.xml output.xml '//name/text()' JAMES
Run Code Online (Sandbox Code Playgroud)