XSLT转换XML为JSON:嵌入原XML并规范化格式问题
XSLT将XML嵌入JSON对象的解决方案
问题说明
我正在编写XSLT,要把输入XML转换成JSON对象,核心需求是将原XML内容作为JSON里的input属性值。目前遇到三个问题:
- 用
<xsl:copy-of select="."/>配合<xsl:output method="text"/>输出时,不仅会出现命名空间相关的输出异常,还因为XML里的双引号未转义,导致最终JSON格式无效 - 若改用
<xsl:output method="xml"/>,XML内容能正常输出,但会自动添加多余的<?xml version="1.0" encoding="UTF-8"?>声明 - 希望去除XML内容里的缩进、换行和多余空格,用
normalized-space处理输出
当前使用的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:uswx="http://nws.weather.gov/schemas/USWX/1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:metce="http://def.wmo.int/metce/2013" xmlns:om="http://www.opengis.net/om/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" exclude-result-prefixes="uswx"> <xsl:output method="text" version="1.0" encoding="UTF-8" indent="no"/> <xsl:template match="/">{ "input": "<xsl:copy-of select="." />" } </xsl:template> </xsl:stylesheet>
输入XML
<?xml version="1.0" encoding="UTF-8"?> <G-AIRMET gml:id="uuid.b3a1b430-b8e0-4943-abb7-796b9a802c49" xmlns="http://nws.weather.gov/schemas/USWX/1.0" xmlns:aixm="http://www.aixm.aero/schema/5.1.1" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:metce="http://def.wmo.int/metce/2013" xmlns:om="http://www.opengis.net/om/2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://nws.weather.gov/schemas/USWX/1.0 http://nws.weather.gov/schemas/USWX/1.0/G-Airmet.xsd"> <airmetStatus xlink:href="https://codes.nws.noaa.gov/NWSI-10-811/ProductStatus/Normal" xlink:title="Normal"></airmetStatus> <productDescription xlink:href="http://codes.nws.weather.gov/NWSI-10-811/AirmetProductDescription/SIERRA" xlink:title="SIERRA"></productDescription> <airmetSeries xlink:href="http://codes.nws.weather.gov/NWSI-10-811/AirmetSeries/S" xlink:title="S"></airmetSeries> <forecastArea>KCI</forecastArea> </G-AIRMET>
当前输出(存在问题)
{ "input": "<?xml version="1.0" encoding="UTF-8"?><G-AIRMET gml:id="uuid.b3a1b430-b8e0-4943-abb7-796b9a802c49" xmlns="http://nws.weather.gov/schemas/USWX/1.0" xmlns:aixm="http://www.aixm.aero/schema/5.1.1" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:metce="http://def.wmo.int/metce/2013" xmlns:om="http://www.opengis.net/om/2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://nws.weather.gov/schemas/USWX/1.0 http://nws.weather.gov/schemas/USWX/1.0/G-Airmet.xsd"> <airmetStatus xlink:href="https://codes.nws.noaa.gov/NWSI-10-811/ProductStatus/Normal" xlink:title="Normal"></airmetStatus> <productDescription xlink:href="http://codes.nws.weather.gov/NWSI-10-811/AirmetProductDescription/SIERRA" xlink:title="SIERRA"></productDescription> <airmetSeries xlink:href="http://codes.nws.weather.gov/NWSI-10-811/AirmetSeries/S" xlink:title="S"></airmetSeries> <forecastArea>KCI</forecastArea> </G-AIRMET>" }
解决方案
要解决这些问题,需要同时处理XML声明去除、JSON字符串转义、空白清理三个核心点,修改后的XSLT代码如下:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:uswx="http://nws.weather.gov/schemas/USWX/1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:metce="http://def.wmo.int/metce/2013" xmlns:om="http://www.opengis.net/om/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" exclude-result-prefixes="uswx xlink metce om gml"> <!-- 主输出为文本格式,生成合法JSON --> <xsl:output method="text" encoding="UTF-8" indent="no"/> <!-- 定义变量存储处理后的XML内容,内部输出省略XML声明 --> <xsl:variable name="xml-content"> <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="no"/> <xsl:copy-of select="."/> </xsl:variable> <xsl:template match="/"> { "input": "<xsl:call-template name="escape-quotes"> <xsl:with-param name="text" select="normalize-space($xml-content)"/> </xsl:call-template>" } </xsl:template> <!-- 转义双引号的模板,确保JSON字符串合法 --> <xsl:template name="escape-quotes"> <xsl:param name="text"/> <xsl:if test="$text != ''"> <xsl:choose> <xsl:when test="contains($text, '"')"> <xsl:value-of select="substring-before($text, '"')"/> <xsl:text>\"</xsl:text> <xsl:call-template name="escape-quotes"> <xsl:with-param name="text" select="substring-after($text, '"')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:if> </xsl:template> </xsl:stylesheet>
关键修改说明
- 去除XML声明:在存储XML内容的变量内部,单独设置
<xsl:output method="xml" omit-xml-declaration="yes"/>,这样生成的XML内容不会带版本声明 - 清理空白:用
normalize-space($xml-content)去掉XML里的所有缩进、换行和连续空格,让内容紧凑 - 转义双引号:通过自定义的
escape-quotes模板,把XML中的双引号转义为\",避免破坏JSON的字符串结构
预期输出
{ "input": "<G-AIRMET gml:id=\"uuid.b3a1b430-b8e0-4943-abb7-796b9a802c49\" xmlns=\"http://nws.weather.gov/schemas/USWX/1.0\" xmlns:aixm=\"http://www.aixm.aero/schema/5.1.1\" xmlns:gml=\"http://www.opengis.net/gml/3.2\" xmlns:metce=\"http://def.wmo.int/metce/2013\" xmlns:om=\"http://www.opengis.net/om/2.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://nws.weather.gov/schemas/USWX/1.0 http://nws.weather.gov/schemas/USWX/1.0/G-Airmet.xsd\"><airmetStatus xlink:href=\"https://codes.nws.noaa.gov/NWSI-10-811/ProductStatus/Normal\" xlink:title=\"Normal\"></airmetStatus><productDescription xlink:href=\"http://codes.nws.weather.gov/NWSI-10-811/AirmetProductDescription/SIERRA\" xlink:title=\"SIERRA\"></productDescription><airmetSeries xlink:href=\"http://codes.nws.weather.gov/NWSI-10-811/AirmetSeries/S\" xlink:title=\"S\"></airmetSeries><forecastArea>KCI</forecastArea></G-AIRMET>" }
内容的提问来源于stack exchange,提问作者ARHassing
相关产品推荐
相关产品推荐

