xml - Xquery在xml中查找表亲

标签 xml xslt xpath xquery

我是xquery的新手,我正在寻找针对此问题的快速解决方案。

我有一个xml文档,我想在文档中找到所有对的第一个表亲和所有对的第二个表亲。

请查看下面的xml,并指导我如何进行操作,或者是否可以提供任何值得高度推广的代码段。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE GEDCOM SYSTEM "file:/Users/indiwarafernando/Downloads/family.dtd">
<GEDCOM>
    <HeaderRec>
        <FileCreation Date=""></FileCreation>
        <Submitter>
            <Link Target="" Ref="FM001"/> 
        </Submitter>
    </HeaderRec>
    <FamilyRec Id="FM001">
        <HusbFath>
            <Link Target="IndividualRec" Ref="IN001"/>
        </HusbFath>
        <WifeMoth>
            <Link Target="IndividualRec" Ref="IN002"/>
        </WifeMoth>
        <Child>
            <Link Target="IndividualRec" Ref="IN004"/>
        </Child>

        <Child>
            <Link Target="IndividualRec" Ref="IN007"/>
        </Child>

    </FamilyRec>


    <FamilyRec Id="FM002">
        <HusbFath>
            <Link Target="IndividualRec" Ref="IN004"/>
        </HusbFath>
        <WifeMoth>
            <Link Target="IndividualRec" Ref="IN005"/>
        </WifeMoth>
        <Child>
            <Link Target="IndividualRec" Ref="IN006"/>
        </Child>

    </FamilyRec>  



    <FamilyRec Id="FM003">
        <HusbFath>
            <Link Target="IndividualRec" Ref="IN007"/>
        </HusbFath>
        <WifeMoth>
            <Link Target="IndividualRec" Ref="IN008"/>
        </WifeMoth>
        <Child>
            <Link Target="IndividualRec" Ref="IN009"/>
        </Child>

    </FamilyRec> 

    <IndividualRec Id="IN001">
        <IndivName>Fathers name</IndivName>                 <!-- This tag used for father of c1 or husband of w1 -->
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="" Ref="IN002"/>
            <Association>Wife</Association>
        </AssocIndiv>
    </IndividualRec>

    <IndividualRec Id="IN002">                                 <!-- This tag used for mother of c1 or wife of h1 -->
        <IndivName>Mother s name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN001"/>
            <Association>Husband</Association>
        </AssocIndiv>
    </IndividualRec>

    <IndividualRec Id="IN003">                                  <!-- This tag used for a child to h1 or w1 or grand son to gm1 or gf1 -->
        <IndivName>Child 1 name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN001"/>
            <Association>Father</Association>
        </AssocIndiv>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN002"/>
            <Association>Mother</Association>
        </AssocIndiv>
    </IndividualRec>




    <IndividualRec Id="IN005">                                 <!-- This tag used for grand mother -->
        <IndivName>Grand mother's name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN004"/>
            <Association>Husband</Association>
        </AssocIndiv>
    </IndividualRec>

    <IndividualRec Id="IN004">                                  <!-- This tag used for grand father -->
        <IndivName>Grand father's name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN005"/>
            <Association>Grand Father's Wife</Association>
        </AssocIndiv>
    </IndividualRec>

    <IndividualRec Id="IN006">                                  <!-- This tag used for a child to h1 or w1 or grand son to gm1 or gf1 -->
        <IndivName>Child 1 name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN004"/>
            <Association>Father</Association>
        </AssocIndiv>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN005"/>
            <Association>Mother</Association>
        </AssocIndiv>
    </IndividualRec>



    <IndividualRec Id="IN007">                                 <!-- This tag used for grand mother -->
        <IndivName>Grand mother's name</IndivName>
        <Gender>Female</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN008"/>
            <Association>Husband</Association>
        </AssocIndiv>
    </IndividualRec>

    <IndividualRec Id="IN008">                                  <!-- This tag used for grand father -->
        <IndivName>Grand father's name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN007"/>
            <Association>Grand Father's Wife</Association>
        </AssocIndiv>
    </IndividualRec>

    <IndividualRec Id="IN009">                                  <!-- This tag used for a child to h1 or w1 or grand son to gm1 or gf1 -->
        <IndivName>Child 1 name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN007"/>
            <Association>Father</Association>
        </AssocIndiv>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN008"/>
            <Association>Mother</Association>
        </AssocIndiv>
    </IndividualRec>



</GEDCOM>


*示例输出:*
一对第一表亲的示例输出是
IN006和IN009

问候
车费

最佳答案

I.这种XSLT 2.0转换(可以很容易地重写为XSLT 1.0)产生了所有的表亲:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:my="my:my" exclude-result-prefixes="my xs">
 <xsl:output method="text"/>

 <xsl:key name="kChildren" match="Child"
  use="../HusbFath/*/@Ref"/>

 <xsl:key name="kChildren" match="Child"
  use="../WifeMoth/*/@Ref"/>

 <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="FamilyRec">
  <xsl:variable name="vGrandChildren" select=
   "my:GrandChildren((HusbFath|WifeMoth)
                            [string(*/@Ref)][1]
                              /*/@Ref
                     )
   "/>
   <xsl:sequence select=
    "for $first in 1 to count($vGrandChildren),
         $second in $first+1 to count($vGrandChildren),
         $grand1 in $vGrandChildren[$first],
         $grand2 in $vGrandChildren[$second]
      return
         if(not($grand1/.. is $grand2/..))
           then (concat('[', $grand1/*/@Ref, ',', $grand2/*/@Ref, '] '))
           else ()
    "/>
 </xsl:template>

 <xsl:template match="text()"/>

 <xsl:function name="my:GrandChildren">
  <xsl:param name="pRef" as="xs:string?"/>

   <xsl:sequence select=
   "key('kChildren',
        key('kChildren', $pRef, $vDoc)/Link/@Ref,
        $vDoc)
   "/>
 </xsl:function>
</xsl:stylesheet>


当此转换应用于提供的XML文档时:

<GEDCOM>
    <HeaderRec>
        <FileCreation Date=""></FileCreation>
        <Submitter>
            <Link Target="" Ref="FM001"/>
        </Submitter>
    </HeaderRec>
    <FamilyRec Id="FM001">
        <HusbFath>
            <Link Target="IndividualRec" Ref="IN001"/>
        </HusbFath>
        <WifeMoth>
            <Link Target="IndividualRec" Ref="IN002"/>
        </WifeMoth>
        <Child>
            <Link Target="IndividualRec" Ref="IN004"/>
        </Child>
        <Child>
            <Link Target="IndividualRec" Ref="IN007"/>
        </Child>
    </FamilyRec>
    <FamilyRec Id="FM002">
        <HusbFath>
            <Link Target="IndividualRec" Ref="IN004"/>
        </HusbFath>
        <WifeMoth>
            <Link Target="IndividualRec" Ref="IN005"/>
        </WifeMoth>
        <Child>
            <Link Target="IndividualRec" Ref="IN006"/>
        </Child>
    </FamilyRec>
    <FamilyRec Id="FM003">
        <HusbFath>
            <Link Target="IndividualRec" Ref="IN007"/>
        </HusbFath>
        <WifeMoth>
            <Link Target="IndividualRec" Ref="IN008"/>
        </WifeMoth>
        <Child>
            <Link Target="IndividualRec" Ref="IN009"/>
        </Child>
    </FamilyRec>
    <IndividualRec Id="IN001">
        <IndivName>Fathers name</IndivName>
        <!-- This tag used for father of c1 or husband of w1 -->
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="" Ref="IN002"/>
            <Association>Wife</Association>
        </AssocIndiv>
    </IndividualRec>
    <IndividualRec Id="IN002">
        <!-- This tag used for mother of c1 or wife of h1 -->
        <IndivName>Mother s name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN001"/>
            <Association>Husband</Association>
        </AssocIndiv>
    </IndividualRec>
    <IndividualRec Id="IN003">
        <!-- This tag used for a child to h1 or w1 or grand son to gm1 or gf1 -->
        <IndivName>Child 1 name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN001"/>
            <Association>Father</Association>
        </AssocIndiv>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN002"/>
            <Association>Mother</Association>
        </AssocIndiv>
    </IndividualRec>
    <IndividualRec Id="IN005">
        <!-- This tag used for grand mother -->
        <IndivName>Grand mother's name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN004"/>
            <Association>Husband</Association>
        </AssocIndiv>
    </IndividualRec>
    <IndividualRec Id="IN004">
        <!-- This tag used for grand father -->
        <IndivName>Grand father's name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN005"/>
            <Association>Grand Father's Wife</Association>
        </AssocIndiv>
    </IndividualRec>
    <IndividualRec Id="IN006">
        <!-- This tag used for a child to h1 or w1 or grand son to gm1 or gf1 -->
        <IndivName>Child 1 name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN004"/>
            <Association>Father</Association>
        </AssocIndiv>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN005"/>
            <Association>Mother</Association>
        </AssocIndiv>
    </IndividualRec>
    <IndividualRec Id="IN007">
        <!-- This tag used for grand mother -->
        <IndivName>Grand mother's name</IndivName>
        <Gender>Female</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN008"/>
            <Association>Husband</Association>
        </AssocIndiv>
    </IndividualRec>
    <IndividualRec Id="IN008">
        <!-- This tag used for grand father -->
        <IndivName>Grand father's name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN007"/>
            <Association>Grand Father's Wife</Association>
        </AssocIndiv>
    </IndividualRec>
    <IndividualRec Id="IN009">
        <!-- This tag used for a child to h1 or w1 or grand son to gm1 or gf1 -->
        <IndivName>Child 1 name</IndivName>
        <Gender>Male</Gender>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN007"/>
            <Association>Father</Association>
        </AssocIndiv>
        <AssocIndiv>
            <Link Target="IndividualRec" Ref="IN008"/>
            <Association>Mother</Association>
        </AssocIndiv>
    </IndividualRec>
</GEDCOM>


所需的正确结果产生了:

[IN006,IN009] 




二。要测试两个Child元素是否为第二亲戚,请在上面添加(并添加必要的代码以测试每对Child对是否为第二亲戚:

 <xsl:key name="kGrandParent" match="HusbFath | WifeMoth"
  use="my:GrandChildren(Link/@Ref)/*/@Ref"/>

 <xsl:function name="my:areFirststCousins" as="xs:boolean">
  <xsl:param name="pPers1" as="element()"/>
  <xsl:param name="pPers2" as="element()"/>

  <xsl:sequence select=
  "key('kGrandParent', $pPers1/*/@Ref, $vDoc)[1]
  is
   key('kGrandParent', $pPers2/*/@Ref, $vDoc)[1]
  and
   not($pPers1/.. is $pPers2/..)
  "/>
 </xsl:function>

 <xsl:function name="my:areSecondCousins" as="xs:boolean">
  <xsl:param name="pPers1" as="element()"/>
  <xsl:param name="pPers2" as="element()"/>

  <xsl:sequence select=
  "my:areFirststCousins($pPers1/../(HusbFath|WifeMoth)[1],
                        $pPers2/../(HusbFath|WifeMoth)[1]
                       )
  "/>
 </xsl:function>




三,完整的解决方案:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:my="my:my" exclude-result-prefixes="my xs">
 <xsl:output method="text"/>

 <xsl:key name="kChildren" match="Child"
  use="../HusbFath/*/@Ref"/>

 <xsl:key name="kChildren" match="Child"
  use="../WifeMoth/*/@Ref"/>

 <xsl:key name="kGrandParent" match="HusbFath | WifeMoth"
  use="my:GrandChildren(Link/@Ref)/*/@Ref"/>

 <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="/*">
  First Cousins:
  <xsl:sequence select=
  "for $first in 1 to count(/*/FamilyRec/Child),
       $second in $first+1 to count(/*/FamilyRec/Child),
       $pers1 in (/*/FamilyRec/Child)[$first],
       $pers2 in (/*/FamilyRec/Child)[$second]
     return
       if(my:areFirststCousins($pers1, $pers2))
         then concat('[', $pers1/*/@Ref, ',', $pers2/*/@Ref, '] ')
         else ()
  "/>

  Second Cousins:
  <xsl:sequence select=
  "for $first in 1 to count(/*/FamilyRec/Child),
       $second in $first+1 to count(/*/FamilyRec/Child),
       $pers1 in (/*/FamilyRec/Child)[$first],
       $pers2 in (/*/FamilyRec/Child)[$second]
     return
       if(my:areSecondCousins($pers1, $pers2))
         then concat('[', $pers1/*/@Ref, ',', $pers2/*/@Ref, '] ')
         else ()
  "/>
 </xsl:template>

 <xsl:function name="my:GrandChildren">
  <xsl:param name="pRef" as="xs:string?"/>

   <xsl:sequence select=
   "key('kChildren',
        key('kChildren', $pRef, $vDoc)/Link/@Ref,
        $vDoc)
   "/>
 </xsl:function>


 <xsl:function name="my:areFirststCousins" as="xs:boolean">
  <xsl:param name="pPers1" as="element()"/>
  <xsl:param name="pPers2" as="element()"/>

  <xsl:sequence select=
  "key('kGrandParent', $pPers1/*/@Ref, $vDoc)[1]
  is
   key('kGrandParent', $pPers2/*/@Ref, $vDoc)[1]
  and
   not($pPers1/.. is $pPers2/..)
  "/>
 </xsl:function>

 <xsl:function name="my:areSecondCousins" as="xs:boolean">
  <xsl:param name="pPers1" as="element()"/>
  <xsl:param name="pPers2" as="element()"/>

  <xsl:sequence select=
  "my:areFirststCousins($pPers1/../(HusbFath|WifeMoth)[1],
                        $pPers2/../(HusbFath|WifeMoth)[1]
                       )
  "/>
 </xsl:function>
</xsl:stylesheet>


当将此转换应用于相同的提供的XML文档(如上)时,将产生正确的结果:

  First Cousins:
  [IN006,IN009] 

  Second Cousins:

关于xml - Xquery在xml中查找表亲,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13781802/

相关文章:

php - 为什么使用 XML 作为存储格式?

java - Android 整数 xml 值到字符串

xml - XML block 的条件计数

xml - 更正用于访问从 REST API 调用检索到的 xml 节点的 xslt/xpath 语法

xml - 遍历 XML 树获取属性值

java - Simple XML 库实际上如何创建和填充对象?

c# - Node.SelectNodes(/*) 和 Node.childNodes 有什么区别?

xml - 使用 XSLT 合并两个 XML 源文档

java - 生成 .xsl 格式的二维码?

xml - 将字符串解析转换为 XQuery 和 XPath