【问题标题】:How to restructure an XML file based on some rules?如何根据一些规则重构 XML 文件?
【发布时间】:2012-08-26 22:54:04
【问题描述】:
我有数千个基于 JSF1.2 的 JSP 文件,但我想迁移到 JSF2.0 并改用 facelets,所以我必须根据 some defined rules 更改它们的结构,例如一些必需的更改如下:
- 我应该删除
<view>标签
- 我应该将
<head> 转换为<h:head>
- 我应该将
<body> 转换为<h:body>
- 我应该更改一些命名空间声明
由于文件数量巨大,我决定开发一个迷你应用程序来自动化这个过程,否则我必须手动修改很多文件!
我想知道这样做的最佳解决方案是什么?我应该使用 XSLT 还是应该将 JSP 文件解析为 XML 文件并通过 DOM 修改它们的结构?
【问题讨论】:
标签:
java
xml
xslt
jsf-2
facelets
【解决方案1】:
这些不是简单的文本替换(您需要向文件添加新的名称空间,即 Facelets 中的 composition 名称空间,文件扩展名从 .JSP 更改为 .XHTML 等),更简单的选择似乎是 XSLT,因为您可以在其中使用某种逻辑,但是,真正使用 Facelets 所需的更改对于任何自动化流程来说都不是一件容易的事。
不要浪费太多时间编写最先进的 JSF 迁移器来实现这一点,尝试做一些可以用最少的努力进行几乎所有更改的事情,然后通过以下方式进行修改手使一切正常。如果您想将 Facelets 中的功能用作模板和复合组件,那么您最终还是要手动重构代码。
【解决方案2】:
我的赌注是 DOM。操作文档并将其另存为新文件(或覆盖)。这只是您可以递归地应用于所有文档的几个规则。
【解决方案3】:
这对于 XSLT 来说是直截了当的。
这是一个执行所有必需替换的示例:
鉴于此 XML 源文件:
<html xmlns:old="old:namespace">
<head>
<meta property="og:type" content="webcontent"/>
</head>
<view>Some View</view>
<body>
The Body here.
</body>
</html>
此转换执行所有请求的更改:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:h="some:h" xmlns:old="old:namespace" xmlns:new="new:new"
exclude-result-prefixes="h new old">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vnsH" select="document('')/*/namespace::h"/>
<xsl:variable name="vnsNew" select="document('')/*/namespace::new"/>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="namespace::*[not(name()='old')]"/>
<xsl:if test="namespace::old">
<xsl:copy-of select="$vnsNew"/>
</xsl:if>
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}" namespace="{namespace-uri()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="node()[not(self::*)]">
<xsl:copy/>
</xsl:template>
<xsl:template match="view"/>
<xsl:template match="/*">
<xsl:element name="{name()}">
<xsl:copy-of select="namespace::*[not(name()='old')]|$vnsH"/>
<xsl:if test="namespace::old">
<xsl:copy-of select="$vnsNew"/>
</xsl:if>
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="head|body">
<xsl:element name="h:{name()}" namespace="some:h">
<xsl:copy-of select="namespace::*[not(name()='old')]"/>
<xsl:if test="namespace::old">
<xsl:copy-of select="$vnsNew"/>
</xsl:if>
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
当应用于上述 XML 文档时,会产生想要的正确结果:
<html xmlns:h="some:h" xmlns:new="new:new">
<h:head>
<meta property="og:type" content="webcontent"/>
</h:head>
<h:body>
The Body here.
</h:body>
</html>
请注意:
<view> 已被删除。
<head> 和 <body> 转换为 <h:head> 和 <h:body>。
old 命名空间现在替换为 new 命名空间。