在现代软件开发中,XML文件因其结构化和可扩展性而被广泛使用。尽管JSON在某些实现中逐渐取代了XML,但直接操作XML文件在某些情况下仍然非常有用,甚至是必要的。对于Java开发者来说,通常通过DOM解析器与XML文档进行交互,但在处理大型文件时,使用专门设计的程序来操作XML文档会更加高效。
虽然在某些特殊情况下,可以使用简单的文本编辑器来处理小型文档,但大型文档的处理则需要更专业的工具。幸运的是,有免费的软件如XML Copy Editor可以满足需求。
在参与的一个项目中,通过SOAP调用与供应商软件进行通信。有时,供应商软件的表现并不如预期,数据可能会被损坏,需要修复。由于无法通过客户端UI来处理这个问题,选择直接操作XML数据,然后通过SOAP调用将其返回给供应商系统。这个过程涉及到多个数据片段,这些数据片段根据地理位置(例如州)进行划分。这些文件可能达到10MB大小,包含所有50个州的条目。根据经验,XML Copy Editor在处理大型文件时从未遇到过困难,这为工作带来了极大的便利。
在接下来的段落中,将不仅介绍XML Copy Editor,还会提供一个关于XML/XSLT/XPath的快速教程。以下是一个简化的XML文件示例,它代表了通常处理的文件类型:
<Header1>
<Header2>
<Detail>
<State>
<Name>Missouri</Name>
</State>
<SubDetail>
<Premium>500</Premium>
</SubDetail>
</Detail>
<Detail>
<State>
<Name>Kansas</Name>
</State>
<SubDetail>
<Premium>600</Premium>
</SubDetail>
</Detail>
</Header2>
</Header1>
通常,在XML Copy Editor中打开文件后的第一个操作是执行“XML → Pretty Print”功能(F11),因为文件通常用于系统间的通信,而不是为了人类阅读。“Pretty Print”功能会格式化文档,添加适当的换行和缩进,使其更易于阅读和解释。
为了找到需要更改的数据,使用XPath。在这个例子中,寻找的是密苏里州的“Premium”元素。从访问“Pretty Print”的同一个菜单中,还可以访问“XML → Evaluate XPath…”(F9),这会弹出一个包含单个文本输入字段的模态对话框。输入的XPath语句是:
\Header1\Header2\Detail\SubDetail\Premium
这个XPath语句相当直接,简单地说,它要求返回所有具有“Header1 → Header2 → Detail → SubDetail → Premium”祖先的节点。然而,这将返回密苏里州和堪萨斯州的两个“Premium”节点,这不是想要的。记住,每个XPath语句都有可能返回多个结果;开发者需要使语句足够精确,以返回所需的结果。换句话说,每个XPath语句都在请求,“给所有满足这个条件的元素。”因此,以以下方式细化这个语句:
\Header1\Header2\Detail\SubDetail\Premium[../../../@State='Missouri']
这个语句的末尾添加的“[../../../@State='Missouri']”可能有点令人困惑,但它是XPath中非常有价值的一部分。“@State='Missouri'”是一个限定符,表示返回“State”节点的值等于“Missouri”的“Premium”元素。如果“State”节点是“Premium”的子节点,那么语句将如下所示:
\Header1\Header2\Detail\SubDetail\Premium[@State='Missouri']
然而,由于“State”节点在祖先链上的位置更高,并且是XPath中的一个元素(第二个“Policy”节点)的兄弟节点,限定符必须“回退”以确定XML中“State”节点的位置。限定符中的每个“../”都是向上一步。可以将其视为类似于Windows命令行中的“cd..”。 现在已经找到了想要更改的数据,必须对其进行更改。XPath本身无法做到这一点,但使用XPath结合XSLT可以实现目标。XSLT通过读取在单独的XSLT文件中定义的“模板”规则来“转换”XML文档。XSLT文件的格式与XML非常相似。可以在XML Copy Editor中创建一个XSLT文件,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="\Header1\Header2\Detail\SubDetail\Premium[@State='Missouri']">
100
</xsl:template>
</xsl:stylesheet>
然后,从菜单中启动“XML → XSL Transform…”(F8)操作。这会弹出一个打开文件对话框,从中选择刚刚定义的XSL文件。这将生成一个新的XML文档,内容如下:
<Header1>
<Header2>
<Detail>
<State>
<Name>Missouri</Name>
</State>
<SubDetail>
<Premium>100</Premium>
</SubDetail>
</Detail>
<Detail>
<State>
<Name>Kansas</Name>
</State>
<SubDetail>
<Premium>600</Premium>
</SubDetail>
</Detail>
</Header2>
</Header1>
这是如何工作的呢?在XSL文件中定义了两个“模板”。模板将规则应用于指定的XML。在这种情况下,第一个模板指示将整个XML复制到输出文件中。第二个模板指示将指示的XPath节点的值更改为定义的值。