如何用XSL结合Java DOM对XML按属性排序并保存?
问题
使用Java DOM读取XML并插入新元素后,希望保存时通过XSL按title属性对XML的<movie>元素排序。
现有XML:
<movie-theater> <catalog> <movie title="StarWars" director="George Lucas" madeIn="Holliwood"/> <movie title="LordOfTheRings" director="Peter Jackson" madeIn="New Zeland"/> <movie title="Batman" director="Tim Burton" madeIn="Holliwood"/> </catalog> </movie-theater>
期望排序后的XML:
<movie-theater> <catalog> <movie title="Batman" director="Tim Burton" madeIn="Holliwood"/> <movie title="LordOfTheRings" director="Peter Jackson" madeIn="New Zeland"/> <movie title="StarWars" director="George Lucas" madeIn="Holliwood"/> </catalog> </movie-theater>
你尝试的XSL模板:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/movie-theater/catalog"> <xsl:for-each select="movie"> <xsl:sort select="@title"/> <xsl:value-of select="."/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
修正方案
你的XSL模板存在两个关键问题:
<xsl:value-of select="."/>仅输出元素的文本内容,但<movie>是自闭合元素,无文本内容,因此不会生成任何节点代码;需用<xsl:copy-of select="."/>复制整个<movie>节点。- 模板仅匹配了
<catalog>节点,未处理外层<movie-theater>根节点,最终输出会丢失XML的整体结构。
正确的XSL模板如下:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 身份模板:原样复制所有未被特定模板匹配的节点和属性,保留XML整体结构 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 针对catalog节点,对内部movie元素按title属性升序排序 --> <xsl:template match="catalog"> <xsl:copy> <xsl:apply-templates select="movie"> <xsl:sort select="@title" order="ascending" case-order="upper-first"/> </xsl:apply-templates> </xsl:copy> </xsl:template> </xsl:stylesheet>
模板说明
- 第一个模板是身份模板,保证XML中未被特殊处理的节点(比如
<movie-theater>根节点)和属性都能原样保留。 - 第二个模板专门处理
<catalog>节点,对其下的<movie>元素按title属性升序排序,再复制每个排序后的节点,实现需求效果。
Java 代码示例
以下是结合DOM修改XML后,使用XSLT转换并保存的完整代码:
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; import org.w3c.dom.Element; public class XmlSortExample { public static void main(String[] args) { try { // 1. 读取XML文件到DOM对象 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); Document doc = dbf.newDocumentBuilder().parse("input.xml"); // 2. 插入新的movie元素(示例操作,可替换为你的业务逻辑) Element newMovie = doc.createElement("movie"); newMovie.setAttribute("title", "Inception"); newMovie.setAttribute("director", "Christopher Nolan"); newMovie.setAttribute("madeIn", "Holliwood"); doc.getElementsByTagName("catalog").item(0).appendChild(newMovie); // 3. 加载XSLT排序模板 TransformerFactory tf = TransformerFactory.newInstance(); StreamSource xsltSource = new StreamSource("sort.xsl"); Transformer transformer = tf.newTransformer(xsltSource); // 4. 执行转换并保存到输出文件 DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult("output.xml"); transformer.transform(source, result); System.out.println("XML已排序并保存成功"); } catch (Exception e) { e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者Lazaruss
相关产品推荐
相关产品推荐

