2012-08-27 72 views
1

从我关于XSLT 1.0 - Concatenate known child nodes, group by unknown parent查询继集团,并在类似的困境,以Group/merge childs of same nodes in xml/xslt when repeating upper nodes,我想要进一步定义我的分组,并变换XSLT 1.0 - 未知父母和父母兄弟姐妹

<root> 
    <object> 
    <entry> 
     <id>apples</id> 
     <parent1> 
      <object_id>1</object_id> 
     </parent1> 
     <parent1> 
      <object_id>2</object_id> 
     </parent1> 
     <parent2> 
      <object_id>3</object_id> 
     </parent2> 
     <parent2> 
      <object_id>4</object_id> 
     </parent2> 
     <parent2> 
      <object_id>5</object_id> 
     </parent2> 
    </entry> 
    </object> 
    <object> 
    <entry> 
     <id>pears</id> 
     <parent1> 
      <object_id>5</object_id> 
     </parent1> 
     <parent1> 
      <object_id>4</object_id> 
     </parent1> 
     <parent2> 
      <object_id>3</object_id> 
     </parent2> 
     <parent2> 
      <object_id>2</object_id> 
     </parent2> 
     <parent2> 
      <object_id>1</object_id> 
     </parent2> 
    </entry> 
    </object> 
    </root> 

<root> 
    <object> 
     <entry> 
      <id>apples</id> 
      <parent1>1-2</parent1> 
      <parent2>3-4-5</parent2> 
     </entry> 
    </object> 
    <object> 
     <entry> 
      <id>pears</id> 
      <parent1>5-4</parent1> 
      <parent2>3-2-1</parent2> 
     </entry> 
    </object> 
    </root> 

我想这样的事情(虽然这整个例子被简化):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" /> 
    <xsl:key name="groupKey" match="/object/*/*/object_id" use="concat(../../id/text(),name(..))"/> 
    <xsl:template match="/"> 
      <xsl:apply-templates select="./*[object_id]"/> 
    </xsl:template> 

    <xsl:template match="/object/*/*[generate-id(object_id)=generate-id(key('groupName',concat(../id/text(),name()))[1])]"> 
      <field> 
        <xsl:attribute name="name"> 
        <xsl:value-of select="local-name()" /> 
       </xsl:attribute> 
       <xsl:for-each select="key('groupName',concat(../id/text(),name()))"> 
        <xsl:if test="not(position()=1)">-</xsl:if> 
        <xsl:value-of select="."/> 
       </xsl:for-each> 
     </field> 
    </xsl:template> 

    </xsl:stylesheet> 

但我对XPath的理解是缺乏的,而这正在整理全部对象在每个父组的第一个分组中(即,连接的键不工作)。

如果有人能帮我整理我的XPath语法,我会非常感激。

在此先感谢!

+0

感谢大家的回答!我真的很感激它,因为我有一段艰难的时间将先进的XSLT压缩在我的大脑中,并且有时间限制。 – gbentley

+0

并感谢您的解释 - 他们确实帮助我了解这些转变,理解它们的工作方式至关重要。 – gbentley

回答

1

这短短的转变

<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="kObjByParentAndId" match="object_id" 
    use="concat(../../id,'+',name(..))"/> 

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

<xsl:template match="*[object_id]"/> 

<xsl:template priority="2" match= 
"*[object_id and 
    generate-id(object_id) 
    = 
    generate-id(key('kObjByParentAndId', concat(../id,'+',name()))[1]) 
    ]"> 
    <xsl:copy> 
     <xsl:for-each select="key('kObjByParentAndId', concat(../id,'+',name()))"> 
     <xsl:if test="position()>1"> - </xsl:if> 
     <xsl:value-of select="."/> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 
</xsl:stylesheet> 

应用时在提供的XML上d ocument

<root> 
    <object> 
     <entry> 
      <id>apples</id> 
      <parent1> 
       <object_id>1</object_id> 
      </parent1> 
      <parent1> 
       <object_id>2</object_id> 
      </parent1> 
      <parent2> 
       <object_id>3</object_id> 
      </parent2> 
      <parent2> 
       <object_id>4</object_id> 
      </parent2> 
      <parent2> 
       <object_id>5</object_id> 
      </parent2> 
     </entry> 
    </object> 
    <object> 
     <entry> 
      <id>pears</id> 
      <parent1> 
       <object_id>5</object_id> 
      </parent1> 
      <parent1> 
       <object_id>4</object_id> 
      </parent1> 
      <parent2> 
       <object_id>3</object_id> 
      </parent2> 
      <parent2> 
       <object_id>2</object_id> 
      </parent2> 
      <parent2> 
       <object_id>1</object_id> 
      </parent2> 
     </entry> 
    </object> 
</root> 

产生想要的,正确的结果:

<root> 
    <object> 
     <entry> 
     <id>apples</id> 
     <parent1>1 - 2</parent1> 
     <parent2>3 - 4 - 5</parent2> 
     </entry> 
    </object> 
    <object> 
     <entry> 
     <id>pears</id> 
     <parent1>5 - 4</parent1> 
     <parent2>3 - 2 - 1</parent2> 
     </entry> 
    </object> 
</root> 

说明

  1. identity rule被用于重建上一层。

  2. 有两个模板覆盖的身份模板 - 一个“删除(有空体),有一个object_id儿童的任何匹配的元素其他(具有较高优先级)被选定为具有一个object_id儿童的任何元素是“在其基团的第一个” - 使用经典Muenchian grouping method

  3. 的Muenchian分组的使用复合key,这是整个组的id和的级联(具有安全分隔符)。任何父母的姓名object_id i在这个小组里。

1

我觉得在这个例子中,你是通过'父'元素拼凑的,并且object_id元素将在组中。因此,您可以像这样定义您的密钥

<xsl:key name="groupKey" match="*[object_id]" use="concat(../id/text(), '|', name())"/> 

请注意,不需要指定父元素的完整路径。如果你想限制它到层次结构的某个部分,你只会这样做。还要注意使用分隔符'|'这里。在这种情况下可能不必要,它通常用于连接的键,以防止两个不同的值对连接到相同的值。

然后,当你被定位在进入元素上,你会得到独特的“父”的元素,像这样:

<xsl:apply-templates 
    select="* 
    [object_id] 
    [generate-id() = generate-id(key('groupKey', concat(../id/text(), '|', name()))[1])]" /> 

然后,当你定位在第一每个不同的“父”的元素,你会得到OBJECT_ID元素,像这样

<xsl:apply-templates select="key('groupKey', concat(../id/text(), '|', name()))/object_id"/> 

如果需要匹配该只想输出的文本以及分隔符的模板。

以下是完整的XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
    <xsl:key name="groupKey" match="*[object_id]" use="concat(../id/text(), '|', name())"/> 

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

    <xsl:template match="entry"> 
     <entry> 
     <xsl:apply-templates select="id|*[object_id][generate-id() = generate-id(key('groupKey', concat(../id/text(), '|', name()))[1])]"/> 
     </entry> 
    </xsl:template> 

    <xsl:template match="*[object_id]"> 
     <xsl:copy> 
     <xsl:apply-templates select="key('groupKey', concat(../id/text(), '|', name()))/object_id"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="object_id"> 
     <xsl:if test="not(position()=1)">-</xsl:if> 
     <xsl:value-of select="."/> 
    </xsl:template> 
</xsl:stylesheet> 

当适用于您的示例XML,下面是输出

<root> 
    <object> 
     <entry> 
     <id>apples</id> 
     <parent1>1-2</parent1> 
     <parent2>3-4-5</parent2> 
     </entry> 
    </object> 
    <object> 
     <entry> 
     <id>pears</id> 
     <parent1>5-4</parent1> 
     <parent2>3-2-1</parent2> 
     </entry> 
    </object> 
</root> 
1

奇怪的是,我的回答你刚才的问题,但不变的小缺陷校正(用于组头形式的身份模板)完全适用于这个问题了。当然,我的回答并没有被接受,但是我发现,讽刺的是,在你发布之前,我已经给你回答了这个问题(显然未尝试过)。

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

<xsl:key name="kParents" match="*[object_id]" use="local-name()" /> 

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

<xsl:template match="*[*/object_id]"> 
    <xsl:variable name="grandparent-id" select="generate-id()" /> 
<xsl:copy> 
    <xsl:apply-templates select="@* | node()[not(object_id)] | 
    *[generate-id()= 
     generate-id(
     key('kParents',local-name())[generate-id(..)=$grandparent-id][1])]" 
     mode="group-head" /> 
</xsl:copy> 
</xsl:template> 

<xsl:template match="*[object_id]" mode="group-head"> 
<xsl:variable name="grandparent-id" select="generate-id(..)" /> 
<xsl:copy> 
    <xsl:apply-templates select="@* | node()[not(self::object_id)]" /> 
    <xsl:for-each select="key('kParents',local-name())[generate-id(..)=$grandparent-id]/object_id"> 
    <xsl:value-of select="." /> 
    <xsl:if test="position() != last()"> - </xsl:if> 
    </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

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

</xsl:stylesheet> 
+0

对不起肖恩,你是对的,我没有尝试你的方法,因为Dimitre的答案是为我的简化版本工作。我将确保我在未来接受答案之前全面测试所有答案,因为我非常感谢在此问题上收到的所有帮助。感谢您花时间回答我的问题! – gbentley

相关问题