【问题标题】:XSL Node Swapping doesn't workXSL 节点交换不起作用
【发布时间】:2017-01-27 21:59:55
【问题描述】:

我正在尝试编写一个 XSL 来整理一些 XML 文件(它们是 Maven 的 POM)。我想要做的是重新排列某些顶级元素的顺序,删除一个元素并按原样复制其余所有元素。原始 XML 的一个示例是:

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.sourceforge.ondex.apps</groupId>
    <name>Ondex</name>
    <version>0.6.0-SNAPSHOT</version>
    <artifactId>installer</artifactId>
    <packaging>pom</packaging>
    <description>NSIS based Installer</description>
    <parent>
        <artifactId>apps</artifactId>
        <groupId>net.sourceforge.ondex</groupId>
        <version>0.6.0-SNAPSHOT</version>
    </parent>
    <organization>
        <name>Ondex Project</name>
        <url>http://www.ondex.org</url>
    </organization>

    <build>
    ...
    </build>
  ...
</project>

这个 XML 几乎可以工作了(使用 Saxon HE-9-7-06J):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math pom"
    xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:pom="http://maven.apache.org/POM/4.0.0"
    >
    <xsl:output method="xml" indent="yes" />

    <xsl:template match="/pom:project">
        <project>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates select="pom:modelVersion" />
            <xsl:apply-templates select="pom:parent" />     
            <xsl:apply-templates select="pom:groupId" />
            <xsl:apply-templates select="pom:artifactId" />
            <xsl:apply-templates select="pom:name" />
            <xsl:apply-templates select="pom:description" />
            <xsl:apply-templates
                select="node() except (pom:modelVersion|pom:parent|pom:groupId|pom:artifactId|pom:name|pom:description|pom:version)" />
        </project>
    </xsl:template>

    <!-- And the usual identity transform for all other nodes --> 
    <xsl:template match="node()|@*">
        <xsl:copy><xsl:apply-templates select="node()|@*" /></xsl:copy>
    </xsl:template>

</xsl:stylesheet>

但是,输出添加了不需要的空白行来代替移动的节点(例如,请参阅描述后的行,最初我有父级):

<?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/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
            <artifactId>apps</artifactId>
            <groupId>net.sourceforge.ondex</groupId>
            <version>0.6.0-SNAPSHOT</version>
      </parent>
   <groupId>net.sourceforge.ondex.apps</groupId>
   <artifactId>installer</artifactId>
   <name>Ondex</name>
   <description>NSIS based Installer</description>





      <packaging>pom</packaging>


      <organization>
            <name>Ondex Project</name>
            <url>http://www.ondex.org</url>
      </organization>

      <build>
      ...
      </build>
  ...
</project>

我做错了什么?请注意,我不想使用xsl:strip-space,因为为了便于阅读,我想保留原始文件中的空格。

【问题讨论】:

  • 那么 XSLT 应该如何识别要删除的空格并保留那些“为了便于阅读而放在原始文件中的”?您的最后一个 &lt;xsl:apply-templates select="node() except (pom:modelVersion|pom:parent|pom:groupId|pom:artifactId|pom:name|pom:description|pom:version)" /&gt; 不会尝试排除任何空白文本。
  • 没有要删除的空格。 XSLT 在移动捕获元素的位置添加空行(例如,代替父元素)。
  • @zakmck 恐怕你误解了这里发生的事情。转换不添加任何空行。它从输入 XML 复制它们。您会发现很难将位于&lt;/parent&gt;&lt;organization&gt; 之间的空白文本节点与位于&lt;/organization&gt;&lt;build&gt; 之间的空白文本节点区别对待。也许您可以通过计算它们包含多少换行符来区分它们?
  • @MartinHonnen,我认为你是对的,我会通过尝试匹配并忽略我正在移动的标签之间的空格来看看我能做些什么。谢谢。

标签: xml xslt xslt-2.0


【解决方案1】:

使用*而不是node()来选择节点:

<xsl:template match="/pom:project">
    <project>
        <xsl:copy-of select="@*" />
        <xsl:apply-templates select="pom:modelVersion" />
        <xsl:apply-templates select="pom:parent" />     
        <xsl:apply-templates select="pom:groupId" />
        <xsl:apply-templates select="pom:artifactId" />
        <xsl:apply-templates select="pom:name" />
        <xsl:apply-templates select="pom:description" />
        <xsl:apply-templates
            select="* except (pom:modelVersion|pom:parent|pom:groupId|pom:artifactId|pom:name|pom:description|pom:version)" />
    </project>
</xsl:template>

<!-- And the usual identity transform for all other nodes --> 
<xsl:template match="node()|@*">
    <xsl:copy><xsl:apply-templates select="node()|@*" /></xsl:copy>
</xsl:template>

工作XSLT 2.0代码here

【讨论】:

  • 不幸的是,这也会删除原始文件中的空白行。为了更好地解释它: 被移动到输出中的正确位置,但我在它最初所在的位置看到了空白行。相反,原始 XML 中的任何其他空白行都会在输出中正确报告,这正是我想要的。
  • 在这种情况下,我建议使用&lt;xsl:strip-space&gt; 去除所有空格并使用&lt;xsl:text&gt; 添加新行以提高可读性。
  • 无法工作,抱歉。我想报告用户在原始 XML 中放置的空间(显然我不知道在哪里)。问题是 XSLT 添加了更多。我想我明白为什么:node() 在一个元素的关闭和下一个元素的打开之间匹配一些东西(新行?),但我不明白什么以及如何摆脱它。跨度>
【解决方案2】:

好的,在您特此写下的答案和cmets之后,我已经意识到发生了什么并找到了解决方法:

正如@michael.hor257k 解释的那样,问题在于匹配元素(例如&lt;/parent&gt;&lt;organization&gt;)之间的换行符被XSL 匹配为节点并仅在输出中报告,从而导致空行。

&lt;xsl:strip-space&gt; 是不够的,因为它会删除这些换行符以及我想保留的手动插入的空白行。

但这是一个好的开始:我对 XML 进行预处理:

sed -E s/'^\s*$'/'<white-line\/>'/ pom.xml  | sponge pom.xml

也就是说,所有“真实”的白线都被标记&lt;white-line /&gt; 替换。所以,现在除了&lt;xsl:strip-space elements="*" /&gt;之外,很容易将它添加到上面的XSL中:

<xsl:template match="pom:white-line">
  <xsl:text>

  </xsl:text>
</xsl:template>

您可能还需要remove starting/trailing blank lines,以避免在根元素之外填充自定义 XML,从而导致错误。

感谢您的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 2018-06-25
    • 2014-01-28
    • 1970-01-01
    相关资源
    最近更新 更多