使用 XSLT 将空格保留在根元素之外
Keeping whitespace outside of root element with XSLT
我正在使用 XSLT 处理 XML 受源代码控制且必须保持人类可读的文档。
因此,我尝试编辑一个文本节点,但保持文档的其余部分完全原样。
我发现根元素外的空白被删除了。特别是 XML 声明和根元素的打开标记之间的换行符,以及文档末尾的换行符。
当我将 indent=yes
属性添加到 xsl:output
元素时,换行符确实出现在文档末尾。但是,XML 声明和根元素的开放标记之间的换行符仍然缺失。
我的样式表缺少什么?
XSLT
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:param name="newVersion"/>
<xsl:template match="/project/version/text()">
<xsl:value-of select="$newVersion" />
</xsl:template>
</xsl:stylesheet>
来源XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.nuance</groupId>
<artifactId>parent-test-repo</artifactId>
<version>0.1.0</version>
</parent>
<artifactId>test-repo-1</artifactId>
<name>test-repo-1</name>
<version>1.1.0</version>
</project>
预期结果 — 只有 /project/version
中的文本已更改
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.nuance</groupId>
<artifactId>parent-test-repo</artifactId>
<version>0.1.0</version>
</parent>
<artifactId>test-repo-1</artifactId>
<name>test-repo-1</name>
<version>2.0.0</version>
</project>
实际结果
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.nuance</groupId>
<artifactId>parent-test-repo</artifactId>
<version>0.1.0</version>
</parent>
<artifactId>test-repo-1</artifactId>
<name>test-repo-1</name>
<version>2.0.0</version>
</project>
如果您使用的是Java,请尝试添加以下行:
transformer.setOutputProperty("http://www.oracle.com/xml/is-standalone", "yes");
虽然 XML 规范允许白色 space 文本作为根元素前后的杂项,但大多数抽象模型(如信息集)和树模型(如 Xdm)不包含此类白色 space文本作为模型中的节点。
因此,就 XSLT 处理器而言,标记 <?xml version="1.0"?><root/>
和 <?xml version="1.0"?> <root/>
生成同一棵树,其文档节点包含单个元素节点作为子节点。只有根元素之外的注释和处理指令才会显示在 Xdm 树中。
所以您的样式表没有做错任何事情,您对保留这种白色 space 文本节点的期望根本不符合规范和您使用的实现。
至于输出,序列化,我想其他 XSLT 处理器可能会在 XML 声明和结果树序列化的根元素之间输出一个换行符。
看看这是否能产生可接受的结果:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://maven.apache.org/POM/4.0.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="project"/>
<xsl:param name="newVersion"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/project/version/text()">
<xsl:value-of select="$newVersion" />
</xsl:template>
</xsl:stylesheet>
我正在使用 XSLT 处理 XML 受源代码控制且必须保持人类可读的文档。
因此,我尝试编辑一个文本节点,但保持文档的其余部分完全原样。
我发现根元素外的空白被删除了。特别是 XML 声明和根元素的打开标记之间的换行符,以及文档末尾的换行符。
当我将 indent=yes
属性添加到 xsl:output
元素时,换行符确实出现在文档末尾。但是,XML 声明和根元素的开放标记之间的换行符仍然缺失。
我的样式表缺少什么?
XSLT
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:param name="newVersion"/>
<xsl:template match="/project/version/text()">
<xsl:value-of select="$newVersion" />
</xsl:template>
</xsl:stylesheet>
来源XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.nuance</groupId>
<artifactId>parent-test-repo</artifactId>
<version>0.1.0</version>
</parent>
<artifactId>test-repo-1</artifactId>
<name>test-repo-1</name>
<version>1.1.0</version>
</project>
预期结果 — 只有 /project/version
中的文本已更改
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.nuance</groupId>
<artifactId>parent-test-repo</artifactId>
<version>0.1.0</version>
</parent>
<artifactId>test-repo-1</artifactId>
<name>test-repo-1</name>
<version>2.0.0</version>
</project>
实际结果
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.nuance</groupId>
<artifactId>parent-test-repo</artifactId>
<version>0.1.0</version>
</parent>
<artifactId>test-repo-1</artifactId>
<name>test-repo-1</name>
<version>2.0.0</version>
</project>
如果您使用的是Java,请尝试添加以下行:
transformer.setOutputProperty("http://www.oracle.com/xml/is-standalone", "yes");
虽然 XML 规范允许白色 space 文本作为根元素前后的杂项,但大多数抽象模型(如信息集)和树模型(如 Xdm)不包含此类白色 space文本作为模型中的节点。
因此,就 XSLT 处理器而言,标记 <?xml version="1.0"?><root/>
和 <?xml version="1.0"?> <root/>
生成同一棵树,其文档节点包含单个元素节点作为子节点。只有根元素之外的注释和处理指令才会显示在 Xdm 树中。
所以您的样式表没有做错任何事情,您对保留这种白色 space 文本节点的期望根本不符合规范和您使用的实现。
至于输出,序列化,我想其他 XSLT 处理器可能会在 XML 声明和结果树序列化的根元素之间输出一个换行符。
看看这是否能产生可接受的结果:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://maven.apache.org/POM/4.0.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="project"/>
<xsl:param name="newVersion"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/project/version/text()">
<xsl:value-of select="$newVersion" />
</xsl:template>
</xsl:stylesheet>