XSLT - 复制列出的节点

时间:2017-10-31 10:23:58

标签: xml xslt

我想生成翻译文件,根据不同的软件版本和客户隐藏一些参数。我的另一个要求是根据生成的列表对Param进行排序。

编辑:我不想准备排除节点列表,因为原始集是动态的,只有找到的指定节点才会被复制。

示例源XML

<?xml version="1.0" ?>
<ns:ParameterElements AllowAdd="True" moreattributes xmlns:ns="http://www.somens.com/schema">
<ParameterFile>
    <Container>
        <Param Name="n1">
            ...
        </Param>
        <Param Name="sth1">
            ...
        </Param>
        <Param Name="toberemoved" ...>
            ...
        </Param>
    </Container>
</ParameterFile>
</ns:ParameterElements>

我确实尝试了很多方法,但这个方法似乎最接近XSL Copy Nodes based on Attribute Value (Like Search)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="paramSortingList" select="('sth1','n1')"/>

<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="ParameterFile/Container/Param">
    <xsl:copy>
        <xsl:copy-of select="@*[name()=$paramSortingList]|node()"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

所以这对我来说是完美的,因为我可以按照我需要的顺序复制节点。

不幸的是,所提出的解决方案不起作用,

编辑:我期望的结果:

<?xml version="1.0" ?>
<ns:ParameterElements AllowAdd="True" moreattributes xmlns:ns="http://www.somens.com/schema">
<ParameterFile>
    <Container>
        <Param Name="sth1">
            ...
        </Param>
        <Param Name="n1">
            ...
        </Param>
    </Container>
</ParameterFile>
</ns:ParameterElements>

请注意我不想准备排除节点的列表,因为该集是动态的,只有复制时才能找到指定的节点。

2 个答案:

答案 0 :(得分:1)

假设至少使用XSLT 2.0,您可以使用

<xsl:template match="ParameterFile/Container/Param[not(@Name = $paramSortingList)]"/>

在样式表中,以确保不会复制不在您名称序列中的Param元素。

如果您转移到Saxon 9.8或Altova 2017或2018支持的XSLT 3.0,您可以将整个缩短为

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

    <xsl:param name="paramSortingList" select="('sth1','n1')"/>

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:template match="ParameterFile/Container/Param[not(@Name = $paramSortingList)]"/>

</xsl:stylesheet>

答案 1 :(得分:1)

使用XSLT 2.0是这里的方法,正如已经回答的那样,但是如果在短期内对XSLT 1.0解决方案感兴趣,那么你将如何做到这一点(使用粗略的字符串操作)< / p>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="paramSortingList" select="'sth1,n1'"/>
<xsl:param name="paramSortingListPlus" select="concat(',', $paramSortingList, ',')"/>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="ParameterFile/Container">
    <xsl:copy>
      <xsl:apply-templates select="Param[contains($paramSortingListPlus, concat(',', @Name, ','))]">
        <xsl:sort select="string-length(substring-before($paramSortingListPlus, concat(',', @Name, ',')))" />
      </xsl:apply-templates>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>