2016-03-30 44 views
1

我有我需要为我的应用程序转换的XML数据(GraphML)。 XML代表一个图形,它具有标签“User”和“Item”的节点以及标签“HAS_HOBBY”和“FRIEND_OF”的边缘。XSLT - 复制图形表示中只能复制一次元素

给定一个特定的用户,我希望得到改变后所有与他至少分享一种爱好的朋友,以及那些爱好(以项目表示)。 “朋友”由“FRIEND_OF”边缘元素表示,业余爱好由“HAS_HOBBY”表示。

我有我的XSLT(我有点新),可以找到需要的项目和朋友,但是在我的逻辑中,我无法设法复制一个朋友一次 - 这是做每个爱好他分享与原始用户。 我这样做是通过检查每个朋友的爱好来了解每个用户的兴趣爱好,并且当有一场比赛时 - 我打印该项目(爱好)(可以)和朋友 - 但是这个朋友每次打印匹配被找到,导致这个朋友多次出现,这是不希望的。

我试图寻找避免这种方法,但我认为我的整个逻辑有缺陷实施此解决方案。虽然我没有其他想法。

这里是我的XSL:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ns="http://graphml.graphdrawing.org/xmlns" 
    xmlns="http://graphml.graphdrawing.org/xmlns" 
    exclude-result-prefixes="ns #default"> 
    <xsl:strip-space elements="*"/> 
    <xsl:output indent="yes"/> 



    <!--Identity template: default copy all content into the output --> 
    <xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
    </xsl:template> 

    <!-- Don't copy tags called 'node or edge' --> 
    <xsl:template match="ns:node" /> 
    <xsl:template match="ns:edge" /> 



    <xsl:template match="ns:node[ns:data[@key='username' and . = 'c']]"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 

    <xsl:variable name="USERID" select="@id"/> 

    <xsl:for-each select="//ns:edge"> 

     <xsl:if test="@source=$USERID"> 

     <xsl:variable name="TARGET" select="@target"/> 
     <xsl:for-each select="//ns:node[@id=$TARGET]"> 
      <!-- finds USERNAME's hobbies --> 

      <xsl:for-each select="//ns:edge[@source=$USERID and @label='HAS_HOBBY']"> 
      <xsl:variable name="HOBBYTARGET" select="@target"/> 
      <xsl:for-each select="//ns:edge[@source=$TARGET and @label='HAS_HOBBY']"> 
       <xsl:if test="@target=$HOBBYTARGET"> 
       <!-- Shared hobby with friend --> 
       <xsl:for-each select="//ns:node[@id=$HOBBYTARGET]"> 
        <xsl:copy> 
        <xsl:apply-templates select="node()|@*"/> 
        </xsl:copy> 
       </xsl:for-each> 


       </xsl:if> 
      </xsl:for-each> 
      </xsl:for-each> 
     </xsl:for-each> 
     </xsl:if> 

     <xsl:if test="@target=$USERID"> 

     <xsl:variable name="SOURCE" select="@source"/> 
     <xsl:for-each select="//ns:node[@id=$SOURCE]"> 
      <!-- finds USERNAME's hobbies --> 

      <xsl:for-each select="//ns:edge[@source=$USERID and @label='HAS_HOBBY']"> 
      <xsl:variable name="HOBBYTARGET" select="@target"/> 
      <xsl:for-each select="//ns:edge[@source=$SOURCE and @label='HAS_HOBBY']"> 
       <xsl:if test="@target=$HOBBYTARGET"> 
       <!-- Shared hobby with friend --> 
       <xsl:for-each select="//ns:node[@id=$HOBBYTARGET]"> 
        <xsl:copy> 
        <xsl:apply-templates select="node()|@*"/> 
        </xsl:copy> 
       </xsl:for-each> 


       </xsl:if> 
      </xsl:for-each> 
      </xsl:for-each> 

     </xsl:for-each> 
     </xsl:if> 
    </xsl:for-each> 

    </xsl:template> 

</xsl:stylesheet> 

在朋友的拷贝丢失的那一刻,但评论“与朋友共享的业余爱好”后,这将是正确的。

我意识到我不能使用'旗'类型的变量(因为它不可能..),并且没有办法拥有数组或类似的数据结构,所以我真的没有想法。

请帮助我找到一个用户的朋友,他分享了至少一个爱好(项目)和爱好自己。

编辑: 样品输入:我添加图形可视化,以及因此它很容易看到

enter image description here

<?xml version="1.0" encoding="UTF-8"?> 
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"> 
<graph id="G" edgedefault="directed"> 

<node id="n2" labels=":Item"><data key="labels">:Item</data><data key="itemId">Q1</data></node> 
<node id="n32" labels=":Item"><data key="labels">:Item</data><data key="itemId">Q8</data></node> 
<node id="n51" labels=":Item"><data key="labels">:Item</data><data key="itemId">Q23</data></node> 
<node id="n897" labels=":Item"><data key="labels">:Item</data><data key="itemId">Q55</data></node> 

<node id="n406727" labels=":User"><data key="labels">:User</data><data key="hobbies">[Ljava.lang.String;@78ba00a3</data><data key="firstName">a</data><data key="imgPath">/uploads/a.png</data><data key="surName">a</data><data key="username">a</data><data key="gender">Male</data><data key="relaStatus">Single</data></node> 
<node id="n406729" labels=":User"><data key="labels">:User</data><data key="hobbies"></data><data key="firstName">b</data><data key="imgPath">/uploads/b.png</data><data key="surName">b</data><data key="username">b</data><data key="gender">Male</data><data key="relaStatus">Single</data></node> 
<node id="n406731" labels=":User"><data key="labels">:User</data><data key="hobbies"></data><data key="blocked">[Ljava.lang.String;@7b800b40</data><data key="firstName">c</data><data key="imgPath">/uploads/c.png</data><data key="surName">c</data><data key="username">c</data><data key="gender">Male</data><data key="relaStatus">Single</data></node> 
<node id="n406734" labels=":User"><data key="labels">:User</data><data key="hobbies"></data><data key="firstName">d</data><data key="imgPath">/uploads/d.png</data><data key="surName">d</data><data key="username">d</data><data key="gender">Male</data><data key="relaStatus">Single</data></node> 

<edge id="e1223400" source="n406727" target="n406729" label="FRIEND_OF"><data key="label">FRIEND_OF</data></edge> 
<edge id="e1223403" source="n406727" target="n406731" label="FRIEND_OF"><data key="label">FRIEND_OF</data></edge> 
<edge id="e1223405" source="n406734" target="n406731" label="FRIEND_OF"><data key="label">FRIEND_OF</data></edge> 
<edge id="e1223405" source="n406727" target="n406734" label="FRIEND_OF"><data key="label">FRIEND_OF</data></edge> 

<edge id="e1223374" source="n406727" target="n2" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 
<edge id="e1223385" source="n406727" target="n51" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 
<edge id="e1223383" source="n406729" target="n2" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 
<edge id="e1223384" source="n406731" target="n2" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 
<edge id="e1223375" source="n406731" target="n51" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 
<edge id="e1223371" source="n406734" target="n897" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 

</graph> 
</graphml> 

而这里的示例输出。你可以看到只有c和b留在结果中,因为他们有共同的兴趣爱好(带有Q的项目)和a。所以d,边缘a-d和Q51,Q8消失了。

enter image description here

<?xml version="1.0" encoding="UTF-8"?> 
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"> 
<graph id="G" edgedefault="directed"> 

<node id="n2" labels=":Item"><data key="labels">:Item</data><data key="itemId">Q1</data></node> 
<node id="n51" labels=":Item"><data key="labels">:Item</data><data key="itemId">Q23</data></node> 

<node id="n406727" labels=":User"><data key="labels">:User</data><data key="hobbies">[Ljava.lang.String;@78ba00a3</data><data key="firstName">a</data><data key="imgPath">/uploads/a.png</data><data key="surName">a</data><data key="username">a</data><data key="gender">Male</data><data key="relaStatus">Single</data></node> 
<node id="n406729" labels=":User"><data key="labels">:User</data><data key="hobbies"></data><data key="firstName">b</data><data key="imgPath">/uploads/b.png</data><data key="surName">b</data><data key="username">b</data><data key="gender">Male</data><data key="relaStatus">Single</data></node> 
<node id="n406731" labels=":User"><data key="labels">:User</data><data key="hobbies"></data><data key="blocked">[Ljava.lang.String;@7b800b40</data><data key="firstName">c</data><data key="imgPath">/uploads/c.png</data><data key="surName">c</data><data key="username">c</data><data key="gender">Male</data><data key="relaStatus">Single</data></node> 

<edge id="e1223400" source="n406727" target="n406729" label="FRIEND_OF"><data key="label">FRIEND_OF</data></edge> 
<edge id="e1223403" source="n406727" target="n406731" label="FRIEND_OF"><data key="label">FRIEND_OF</data></edge> 
<edge id="e1223405" source="n406734" target="n406731" label="FRIEND_OF"><data key="label">FRIEND_OF</data></edge> 

<edge id="e1223374" source="n406727" target="n2" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 
<edge id="e1223385" source="n406727" target="n51" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 
<edge id="e1223383" source="n406729" target="n2" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 
<edge id="e1223384" source="n406731" target="n2" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 
<edge id="e1223375" source="n406731" target="n51" label="HAS_HOBBY"><data key="label">HAS_HOBBY</data></edge> 

</graph> 
</graphml> 

谢谢您的时间。

编辑#2:增加了标签的节点和边hasLabel数据:

<node id="n3" labels=":Label"><data key="labels">:Label</data><data key="en-gb">Universe</data> 
<edge id="e0" source="n2" target="n3" label="hasLabel"><data key="label">hasLabel</data></edge> 

该边缘连接,其具有Q1的的itemId到具有它的标签,“宇宙”节点n3节点n2。

+1

是对样品输入到XSLT?如果是这样,我没有找到足够的数据将它与您对XML的解释联系起来。您能否重新解释说明并在XML中提供更多的输入。预期的输出会有很大的帮助。 –

+0

将添加输入和预期的输出 – Zephyer

+0

@LingamurthyCS更新了数据和输入可视化图 – Zephyer

回答

1

下面是使用XSLT 2.0的例子(由撒克逊9的支持, XmlPrime,Altova的,Exselt)使用按键来引用的项目和然后集操作,如intersect仅输出共享节点:

<?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" 
    xpath-default-namespace="http://graphml.graphdrawing.org/xmlns" 
    version="2.0"> 

<xsl:param name="user-name" as="xs:string" select="'c'"/> 

<xsl:output indent="yes"/> 

<xsl:key name="user-name" match="node[@labels = ':User']" use="data[@key = 'username']"/> 

<xsl:key name="node-id" match="node" use="@id"/> 

<xsl:key name="source-friends" match="edge[@label = 'FRIEND_OF']" use="@source"/> 
<xsl:key name="target-friends" match="edge[@label = 'FRIEND_OF']" use="@target"/> 
<xsl:key name="source-hobbies" match="edge[@label = 'HAS_HOBBY']" use="@source"/> 

<xsl:variable name="start-node" select="key('user-name', $user-name)"/> 

<xsl:variable name="start-friends" 
       select="key('node-id', key('source-friends', $start-node/@id)/@target) | 
         key('node-id', key('target-friends', $start-node/@id)/@source)"/> 

<xsl:variable name="start-hobbies" select="key('node-id', key('source-hobbies', $start-node/@id)/@target)"/> 

<xsl:variable name="friends-with-shared-hobby" select="$start-friends[key('node-id', key('source-hobbies', @id)/@target) intersect $start-hobbies]"/> 

<xsl:variable name="shared-hobbies" select="$start-hobbies intersect key('node-id', key('source-hobbies', $friends-with-shared-hobby/@id)/@target)"/> 

<xsl:template match="/*"> 
    <xsl:copy> 
     <xsl:copy-of select="$start-node | $friends-with-shared-hobby | $shared-hobbies"/> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 
+0

感谢马丁 - 这似乎适用于'a'!然而,当我提供用户名='B'或用户名='C'时,我只获取用户元素'b'或'c',而没有爱好,也没有'a'(与b和c共享爱好) )。 我使用撒克逊9. 我认为这是因为你在这里考虑到 ““ 只有在源中的朋友。但朋友也可以在FRIENDS_OF边缘的目标。你可以请修改解决方案,包括?非常感谢。 – Zephyer

+0

例如,该边缘 - a是n406727,并且b是n406729。 因此,从a的角度来看,b是'目标'边缘的朋友,但从b的角度来看,a是边缘'源'中的朋友。我相信这就是缺乏完整的解决方案 – Zephyer

+0

@Zephyer,我已更正了代码示例,并添加了另一个键以在两个方向上遍历好友引用。 –

1

问:*他所有的朋友与他至少有一个爱好.. *
这里有第一个可能性做到这一点。

为用户标识创建一个包含所有兴趣边缘的变量。:

<xsl:variable name="hobbies" select="//ns:edge[@source=$USERID and @label='HAS_HOBBY']"/> 

同样为所有的朋友(边缘):

<xsl:variable name="friends" select="//ns:edge[@target=$USERID and @label='FRIEND_OF']"/> 

比相同爱好的朋友应该是:

<xsl:variable name="friends_with_bobby" 
    select="$friends[ //ns:edge[ @label='HAS_HOBBY' and 
     @target = $hobbies/@target]/@source=./@source ]"/> 

为了测试这种尝试:

<xsl:template match="ns:node[ns:data[@key='username' and . = 'c']]"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 

    <xsl:variable name="USERID" select="@id"/> 

    <xsl:variable name="hobbies" select="//ns:edge[@source=$USERID and @label='HAS_HOBBY']"/> 
    <xsl:variable name="friends" select="//ns:edge[@target=$USERID and @label='FRIEND_OF']"/> 
    <xsl:variable name="friends_with_bobby" select="$friends[ //ns:edge[ @label='HAS_HOBBY' and @target = $hobbies/@target]/@source=./@source ]"/> 
    <hobbies> 
     <xsl:copy-of select="$hobbies" /> 
    </hobbies> 
    <friends> 
     <xsl:copy-of select="$friends" /> 
    </friends> 
    <friends_with_bobby> 
     <xsl:copy-of select="$friends_with_bobby" /> 
    </friends_with_bobby> 
</xsl:template> 

这只是边缘,但应该很容易适应y我们要求的输出。 (否则让我知道)

更新: 要获得相同爱好的所有用户(不是必须的朋友)尝试:

<xsl:variable name="shared_hobby" select="//ns:edge[ @label='HAS_HOBBY' and @target = $hobbies/@target]"/> 
    <xsl:variable name="n_user_shared_hobby" select="//ns:node[ns:data[@key='username'] and @id=$shared_hobby/@source]"/>