Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml xslt中前面同级的每个循环缺少第一个元素_Xml_Xslt_Foreach_Xsl Fo - Fatal编程技术网

Xml xslt中前面同级的每个循环缺少第一个元素

Xml xslt中前面同级的每个循环缺少第一个元素,xml,xslt,foreach,xsl-fo,Xml,Xslt,Foreach,Xsl Fo,我在使用XSLT通过属性对xml条目进行分组时遇到了一个问题 以下是我的源xml: <chron> <chronEntry type="education" order="1" blockorder="1"> <foo>bar</foo> </chronEntry> <chronEntry type="education" order="2" blockorder="1"> <foo>bar<

我在使用XSLT通过属性对xml条目进行分组时遇到了一个问题

以下是我的源xml:

<chron>
<chronEntry type="education" order="1" blockorder="1">
    <foo>bar</foo>
</chronEntry>
    <chronEntry type="education" order="2" blockorder="1">
<foo>bar</foo>
    </chronEntry>
<chronEntry type="education" order="3" blockorder="1">
    <foo>bar</foo>
</chronEntry>
<chronEntry type="communityservice" order="1" blockorder="2">
    <foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="1" blockorder="3">
    <foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="2" blockorder="3">
    <foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="3" blockorder="3">
    <foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="4" blockorder="3">
    <foo>bar</foo>
</chronEntry>
</chron>

酒吧
酒吧
酒吧
酒吧
酒吧
酒吧
酒吧
酒吧
我想要得到的是属性“type”的所有可用值的列表。在这种情况下,应为: -教育 -社区服务 -经历

我是这样尝试的:

<xsl:for-each select="/foobar/chron/chronEntry">
            <xsl:sort select="@blockorder"/>
                <xsl:if test ="@blockorder != preceding-sibling::chronEntry[1]/@blockorder">
                    <fo:table-row>
                        <fo:table-cell>
                            <fo:block><xsl:value-of select="@type"/></fo:block>
                        </fo:table-cell>
                    </fo:table-row>
                </xsl:if>
            </xsl:for-each>
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kType" match="@type" use="."/>

 <xsl:template match=
  "chronEntry
    [generate-id(@type)
    =
     generate-id(key('kType', @type)[1])
    ]">
     <xsl:value-of select="concat(@type, ' ')"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

我得到的是: -社区服务 -经历

我错过了“教育”(第一个)

我能做些什么来得到它

谢谢你的帮助

格里茨


Dave

问题在于,尽管您正在创建排序节点列表,但前面的同级:(或任何轴)只能用于表示文档中节点之间的关系(而不是节点列表中的关系)

因此,
前面的同级::
chronEntry[1]
选择当前文档中上下文节点的第一个前面的同级
chronEntry`,而不是在排序节点列表中

解决方案

  • 在XSLT1.0中,捕获变量中每个的
    xsl:for的结果。由于这是臭名昭著的RTF类型,因此必须使用XSLT 1.0处理器支持的
    xxx:node-set()
    扩展函数将其转换为常规树。然后,在此常规树中,轴(包括前面的同级:
    )具有所需的含义

  • 建议的解决方案。使用Muenchian分组:

  • 像这样:

    <xsl:for-each select="/foobar/chron/chronEntry">
                <xsl:sort select="@blockorder"/>
                    <xsl:if test ="@blockorder != preceding-sibling::chronEntry[1]/@blockorder">
                        <fo:table-row>
                            <fo:table-cell>
                                <fo:block><xsl:value-of select="@type"/></fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                    </xsl:if>
                </xsl:for-each>
    
    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:key name="kType" match="@type" use="."/>
    
     <xsl:template match=
      "chronEntry
        [generate-id(@type)
        =
         generate-id(key('kType', @type)[1])
        ]">
         <xsl:value-of select="concat(@type, ' ')"/>
     </xsl:template>
     <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    问题在于,尽管您正在创建排序节点列表,但前面的同级::(或任何轴)只能用于表示文档中节点之间的关系(而不是节点列表中的关系)

    因此,
    前面的同级::
    chronEntry[1]
    选择当前文档中上下文节点的第一个前面的同级
    chronEntry`,而不是在排序节点列表中

    解决方案

  • 在XSLT1.0中,捕获变量中每个的
    xsl:for的结果。由于这是臭名昭著的RTF类型,因此必须使用XSLT 1.0处理器支持的
    xxx:node-set()
    扩展函数将其转换为常规树。然后,在此常规树中,轴(包括前面的同级:
    )具有所需的含义

  • 建议的解决方案。使用Muenchian分组:

  • 像这样:

    <xsl:for-each select="/foobar/chron/chronEntry">
                <xsl:sort select="@blockorder"/>
                    <xsl:if test ="@blockorder != preceding-sibling::chronEntry[1]/@blockorder">
                        <fo:table-row>
                            <fo:table-cell>
                                <fo:block><xsl:value-of select="@type"/></fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                    </xsl:if>
                </xsl:for-each>
    
    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:key name="kType" match="@type" use="."/>
    
     <xsl:template match=
      "chronEntry
        [generate-id(@type)
        =
         generate-id(key('kType', @type)[1])
        ]">
         <xsl:value-of select="concat(@type, ' ')"/>
     </xsl:template>
     <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    您真的需要xsl:sort吗?还是你用它来分组?如果是这样,您只需删除xsl:sort并更正xsl:if测试:

            <xsl:for-each select="/foobar/chron/chronEntry">
                <xsl:if test ="not(@blockorder = preceding-sibling::chronEntry/@blockorder)">
                    <fo:table-row>
                        <fo:table-cell>
                            <fo:block><xsl:value-of select="@type"/></fo:block>
                        </fo:table-cell>
                    </fo:table-row>
                </xsl:if>
            </xsl:for-each>
    
    
    
    如果需要xsl:sort,可以使用:

            <xsl:variable name="types" select="/foobar/chron/chronEntry[not(preceding-sibling::*/@blockorder=@blockorder)]"/>
            <xsl:for-each select="$types">
                <xsl:sort select="@blockorder"/>
                <fo:table-row>
                    <fo:table-cell>
                        <fo:block>
                            <xsl:value-of select="@type"/>
                        </fo:block>
                    </fo:table-cell>
                </fo:table-row>
            </xsl:for-each>
    

    您真的需要xsl:sort吗?还是你用它来分组?如果是这样,您只需删除xsl:sort并更正xsl:if测试:

            <xsl:for-each select="/foobar/chron/chronEntry">
                <xsl:if test ="not(@blockorder = preceding-sibling::chronEntry/@blockorder)">
                    <fo:table-row>
                        <fo:table-cell>
                            <fo:block><xsl:value-of select="@type"/></fo:block>
                        </fo:table-cell>
                    </fo:table-row>
                </xsl:if>
            </xsl:for-each>
    
    
    
    如果需要xsl:sort,可以使用:

            <xsl:variable name="types" select="/foobar/chron/chronEntry[not(preceding-sibling::*/@blockorder=@blockorder)]"/>
            <xsl:for-each select="$types">
                <xsl:sort select="@blockorder"/>
                <fo:table-row>
                    <fo:table-cell>
                        <fo:block>
                            <xsl:value-of select="@type"/>
                        </fo:block>
                    </fo:table-cell>
                </fo:table-row>
            </xsl:for-each>
    
    
    
    您使用的是XSLT 1.0还是XSLT 2.0?您使用的是XSLT 1.0还是XSLT 2.0?