【问题标题】:XSLT Parent child traversing not working properly [closed]XSLT父子遍历无法正常工作[关闭]
【发布时间】:2012-08-27 22:03:49
【问题描述】:

这是真实的场景,只是我更改了数据。我有以下父子关系xml。我正在尝试使用 XSLT 转换以下 xml。我能够遍历父数据,但无法为子节点提供条件,例如子引用是否在任何时候发生变化,它应该分隔样本,否则它应该由子节点分隔。

输入文件

<Samples>
    <Sample>
        <a1>a1name</a1>
        <b1>b1desc</b1>
        <c1ref>101</c1ref>
        <childref>101</childref>
        <eno>test</eno>
        <ename>somename</ename>
    </Sample>
    <Sample>
        <a1>a1name</a1>
        <b1>b1desc</b1>
        <c1ref>101</c1ref>
        <childref>101</childref>
        <eno>test123</eno>
        <ename>someothername</ename>
    </Sample>
    <Sample>
        <a1>a1name1</a1>
        <b1>b1desc1</b1>
        <c1ref>102</c1ref>
        <childref>102</childref>
        <eno>test1234</eno>
        <ename>someothername1</ename>
    </Sample>
    <Sample>
        <a1>a1name</a1>
        <b1>b1desc</b1>
        <c1ref>101</c1ref>
        <childref>101</childref>
        <eno>test</eno>
        <ename>somename</ename>
    </Sample>
    <Sample>
        <a1>a1name1</a1>
        <b1>b1desc1</b1>
        <c1ref>103</c1ref>
        <childref>103</childref>
        <eno>test1234</eno>
        <ename>someothername1</ename>
    </Sample>
</Samples>

OP 没有解释的东西。可能是预期的输出文档

<Samples>
    <Sample>
        <a1>a1name</a1>
        <b1>b1desc</b1>
        <c1ref>101</c1ref>
        <childs>
            <childref>101</childref>
            <eno>test</eno>
            <ename>somename</ename>
        </childs>
        <childs>
            <childref>101</childref>
            <eno>test123</eno>
            <ename>someothername</ename>
        </childs>
    </Sample>
    <Sample>
        <a1>a1name1</a1>
        <b1>b1desc1</b1>
        <c1ref>102</c1ref>
        <childs>
            <childref>102</childref>
            <eno>test1234</eno>
            <ename>someothername1</ename>
        </childs>
    </Sample>
</Samples>

下面的 XSLT 工作,但它再次重复 childref 101。

    <?xml version="1.0" encoding="UTF-8"?> 
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0">       
    <xsl:output indent="yes" method="xml"/>
    <xsl:template match="Samples">     
    <xsl:copy>         
    <!-- select the first Sample -->
    <xsl:apply-templates select="Sample[1]"/>
    </xsl:copy> </xsl:template>  
    <xsl:template match="Sample">
    <!-- the a1 attribute in Sample will act as the identifier 
    (check if it is the same      element) -->     
    <xsl:variable name="identifier" select="a1"/>
     <xsl:copy>         
      <xsl:apply-templates select="a1"/> 
        <xsl:apply-templates select="b1"/>
         <xsl:apply-templates select="c1ref"/>
         <xsl:element name="childs">
             <xsl:apply-templates select="childref"/>
             <xsl:apply-templates select="eno"/>
             <xsl:apply-templates select="ename"/>
         </xsl:element>         
         <!-- get childs of Sample with same identifier -->
         <xsl:apply-templates 
         select="following-sibling::Sample[a1=$identifier]"
         mode="SameElement"/>     
</xsl:copy>     
<!-- select the nex Samples with different identifier -->
<xsl:apply-templates select="following-sibling::Sample[a1!=$identifier][1]"/>      </xsl:template>
<xsl:template match="Sample" mode="SameElement">
     <!-- here only output the child elements -->
     <xsl:element name="childs">
         <xsl:apply-templates select="childref"/>
         <xsl:apply-templates select="eno"/>
         <xsl:apply-templates select="ename"/>
     </xsl:element> </xsl:template>
<xsl:template match="*|@*|text()"> 
    <xsl:copy>
         <xsl:apply-templates/>
     </xsl:copy> 
</xsl:template> 
</xsl:stylesheet>      

如何编写 xslt 以产生上述输出?

【问题讨论】:

  • 您好 SSdev,我很想推荐一个 Muenchian 分组(例如 stackoverflow.com/questions/1753485/…)。你试过了吗?最好的问候,彼得
  • 我使用的上述 XSLT 几乎是正确的,只是它再次重复了已经包含在 标记中的子节点。
  • SSdev,您在样式表中说“version=1.0”并将其标记为“xslt-2.0”。我下面的解决方案是 1.0。下次请注意这些规范,因为 XSLT 1.0 和 2.0 在分组方面存在很大差异。
  • SSdev,除非您编辑问题并提供所需的确切结果,否则无论读者的精神力量如何,都无法猜到。请。
  • @Peter:这个问题被标记为 xslt-1.0。删除该标签的不是 SSdev。

标签: xslt grouping xslt-1.0 xslt-2.0


【解决方案1】:

说实话,我无法找出您的 XSLT 中的错误。所以我想出了我自己的版本,使用层次分组(由 Jeni Tennison 描述)。这是一个 XSLT 1.0 解决方案。如果我使用这个输入 XML:

<?xml version="1.0" encoding="UTF-8"?>
<Samples>
<Sample>
    <a1>a1name</a1>
    <b1>b1desc</b1>
    <c1ref>101</c1ref>
    <childref>101</childref>
    <eno>test</eno>
    <ename>somename</ename>
</Sample>
<Sample>
    <a1>a1name</a1>
    <b1>b1desc</b1>
    <c1ref>101</c1ref>
    <childref>101</childref>
    <eno>test123</eno>
    <ename>someothername</ename>
</Sample>
<Sample>
    <a1>a1name1</a1>
    <b1>b1desc1</b1>
    <c1ref>102</c1ref>
    <childref>102</childref>
    <eno>test1234</eno>
    <ename>someothername1</ename>
</Sample>
<Sample>
    <a1>a1name</a1>
    <b1>b1desc</b1>
    <c1ref>101</c1ref>
    <childref>101</childref>
    <eno>test</eno>
    <ename>somename</ename>
</Sample>
<Sample>
    <a1>a1name1</a1>
    <b1>b1desc1</b1>
    <c1ref>103</c1ref>
    <childref>103</childref>
    <eno>test1234</eno>
    <ename>someothername1</ename>
</Sample>
</Samples>

并应用此 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="xml" indent="yes"/>

<xsl:key name="keyByc1ref" match="Sample" use="c1ref"/>

<xsl:template match="Samples">
    <xsl:variable name="uniqueSet" select="Sample[generate-id()=generate-id(key('keyByc1ref',c1ref)[1])]"/>
    <Samples>
        <xsl:apply-templates select="$uniqueSet" mode="group"/>
    </Samples>
</xsl:template>

<xsl:template match="Sample" mode="group">
    <Sample>
        <xsl:copy-of select="a1"/>
        <xsl:copy-of select="b1"/>
        <xsl:apply-templates select="key('keyByc1ref',c1ref)" mode="item"/>
    </Sample>
</xsl:template>

<xsl:template match="Sample" mode="item">
    <childs>
        <xsl:copy-of select="childref"/>
        <xsl:copy-of select="eno"/>
        <xsl:copy-of select="ename"/>
    </childs>
</xsl:template>

</xsl:stylesheet>

我得到了这个 XML 输出。我认为它看起来不错,我不确定预期的输出:

<?xml version="1.0" encoding="UTF-8"?>
<Samples>
<Sample>
    <a1>a1name</a1>
    <b1>b1desc</b1>
    <childs>
        <childref>101</childref>
        <eno>test</eno>
        <ename>somename</ename>
    </childs>
    <childs>
        <childref>101</childref>
        <eno>test123</eno>
        <ename>someothername</ename>
    </childs>
    <childs>
        <childref>101</childref>
        <eno>test</eno>
        <ename>somename</ename>
    </childs>
</Sample>
<Sample>
    <a1>a1name1</a1>
    <b1>b1desc1</b1>
    <childs>
        <childref>102</childref>
        <eno>test1234</eno>
        <ename>someothername1</ename>
    </childs>
</Sample>
<Sample>
    <a1>a1name1</a1>
    <b1>b1desc1</b1>
    <childs>
        <childref>103</childref>
        <eno>test1234</eno>
        <ename>someothername1</ename>
    </childs>
</Sample>
</Samples>

使用开头的键,您可以识别所有独特的项目集。对于每个标识的组,您运行“mode=group”模板,该模板复制 a1 和 b1,并调用将其他 3 个元素复制到子节点的 item-template。

【讨论】:

    【解决方案2】:

    这是一个分组问题,可以使用xsl:for-each-group 轻松解决。

    但是,我还没有设法从您的示例中准确计算出您的分组标准,因此我无法为您提供准确的代码。

    【讨论】:

    • 谢谢迈克尔。分组或排序应该在 c1ref 上工作。如果你看到上面的 xml c1ref 和 childref 是一样的。因此,无论它们在样本中是否相同,它们都应该出现在单个样本中。否则它应该出现在单独的 Sample 标签中。
    • 那你要&lt;xsl:for-each-group select="Sample" group-by="c1ref"&gt;
    猜你喜欢
    • 1970-01-01
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多