如何使用XSL将几个新元素插入到另一个元素中,保持其他所有元素不变

时间:2015-01-22 14:17:01

标签: xml xslt rdf

我编写了一个XSLT,它应该添加一个或多个skos:父rdf:Description元素中的较窄元素。这是一个起始的xml:

<rdf:Description rdf:about="http://schema.xxx.com/ns/vocabulary-structure/AAA">
        <rdf:type rdf:resource="http://www.w3.org/2004/02/skos/core#Concept"/>
        <skos:prefLabel xml:lang="en">AAA</skos:prefLabel>
        <skos:broader rdf:resource="http://schema.xxx.com/ns/vocabulary-structure/AA"/>
    </rdf:Description>

我希望为xml中的每个较窄元素添加一个元素:

   <rdf:Description rdf:about="http://schema.xxx.com/ns/vocabulary-structure/AAA">
      <skos:narrower rdf:resource="http://schema.xxx.com/ns/vocabulary-structure/AAAA"/>
      <rdf:type rdf:resource="http://www.w3.org/2004/02/skos/core#Concept"/>
      <skos:prefLabel xml:lang="en">AAA</skos:prefLabel>
      <skos:broader rdf:resource="http://schema.xxx.com/ns/vocabulary-structure/AA"/>   
   </rdf:Description>

我需要这样做才能指定skos:wide和skos:更窄的关系(我使用的词汇工具只存储skos:更广泛)。

我写的xsl就是这样做的。然而,虽然结果接近我想要的,但它有一个缺陷。如果元素AAA除了AAAA之外还有一个更窄的元素AAAB,那么我得到一个单独的 rdf:Description元素:

   <rdf:Description rdf:about="http://schema.xxx.com/ns/vocabulary-structure/AAA">
      <skos:narrower rdf:resource="http://schema.xxx.com/ns/vocabulary-structure/AAAB"/>        
      <rdf:type rdf:resource="http://www.w3.org/2004/02/skos/core#Concept"/>
      <skos:prefLabel xml:lang="en">AAA</skos:prefLabel>
      <skos:broader rdf:resource="http://schema.xxx.com/ns/vocabulary-structure/AA"/>
   </rdf:Description>

我想要的是两个skos:更窄的指向AAAA,指向AAAB的指向同一个AAA元素,而不是两个单独的元素。

这是xslt的(我希望)相关部分。任何人都可以建议我做错了吗?

<xsl:template match="rdf:RDF/rdf:Description" mode="apply-skos-narrower">
    <xsl:param name="this-concept-id"/>
    <xsl:param name="narrower-concept-id"/>
        <xsl:choose>
            <xsl:when test="@rdf:about=$this-concept-id">
                <xsl:copy>
                    <xsl:copy-of select="@*|node()"/>
                    <skos:narrower>
                        <xsl:attribute name="rdf:resource">
                            <xsl:value-of select="$narrower-concept-id"/>
                        </xsl:attribute>
                    </skos:narrower>
                    <xsl:copy-of select="node()"/>
                </xsl:copy>         
            </xsl:when>
        </xsl:choose>       
</xsl:template>

感谢您的评论。以下是所要求的完整xslt。我确信我在这里误解了关于递归是如何工作的,所以任何指导都会非常感激。

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" version="1.0"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:skos="http://www.w3.org/2004/02/skos/core#"
>
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <!-- Store the vocabulary identifier as a variable -->
    <xsl:variable name="vocabulary-id" select = "//rdf:Description[child::rdf:type[@rdf:resource='http://www.w3.org/2002/07/owl#Ontology']]/@rdf:about" />

<!-- Replace the massive collection of namespace declarations provided by EVN with a more sensible minimal set, then call the first processing template. -->
    <xsl:template match="/">
        <rdf:RDF xmlns:opencyc="http://sw.opencyc.org/concept/"
            xmlns:freebase="http://rdf.freebase.com/ns/" 
            xmlns:owl="http://www.w3.org/2002/07/owl#"
            xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
            xmlns:dcterms="http://purl.org/dc/terms/" 
            xmlns:skos="http://www.w3.org/2004/02/skos/core#"
            xmlns:dbpedia="http://dbpedia.org/resource/"
            xmlns:sesame="http://www.openrdf.org/schema/sesame#"
            xmlns:cycAnnot="http://sw.cyc.com/CycAnnotations_v1#" 
            xmlns:ctag="http://commontag.org/ns#"
            xmlns:foaf="http://xmlns.com/foaf/0.1/" 
            xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
            xmlns:cyc="http://sw.cyc.com/concept/" 
            xmlns:dc="http://purl.org/dc/elements/1.1/"
            xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
            <!-- Copy the header and Concept Scheme sections - these are fine -->
            <xsl:apply-templates select="/rdf:RDF/rdf:Description" mode="process-vocabulary-header"/>
            <xsl:apply-templates select="/rdf:RDF/rdf:Description" mode="process-concept-scheme"/>
            <!-- Now process all of the other concepts -->
            <xsl:apply-templates select="/rdf:RDF/rdf:Description" mode="process-other-concepts"/>
        </rdf:RDF>
    </xsl:template>

    <!-- Process the vocabulary header information -->
    <xsl:template match="rdf:RDF/rdf:Description" mode="process-vocabulary-header">
        <xsl:if test="rdf:type[@rdf:resource='http://www.w3.org/2002/07/owl#Ontology']">
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:template>

    <!-- Process the ConceptScheme element -->
    <xsl:template match="rdf:Description" mode="process-concept-scheme">
        <xsl:if test="rdf:type[@rdf:resource='http://www.w3.org/2004/02/skos/core#ConceptScheme']">
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:template>

    <xsl:template match="rdf:RDF/rdf:Description" mode="process-other-concepts">
        <xsl:choose>
            <!-- When we are in the ConceptScheme element, we can get the concepts that have hasTopConcept elements and set the complementary topConceptOf elements -->
            <xsl:when test="rdf:type[@rdf:resource='http://www.w3.org/2004/02/skos/core#ConceptScheme']">
                <xsl:for-each select="skos:hasTopConcept">
                    <xsl:apply-templates select="/rdf:RDF/rdf:Description" mode="apply-top-concepts">
                        <xsl:with-param name="top-concept-id" select="@rdf:resource"/>
                    </xsl:apply-templates>
                </xsl:for-each>
            <!-- Finally, find the elements with skos:broader elements and set their complementary skos:narrower elements -->
            </xsl:when>
            <xsl:when test="skos:broader">
                <xsl:apply-templates select="/rdf:RDF/rdf:Description" mode="apply-skos-narrower">
                    <xsl:with-param name="this-concept-id" select="skos:broader/@rdf:resource"/>
                    <xsl:with-param name="narrower-concept-id" select="./@rdf:about"></xsl:with-param>
                </xsl:apply-templates>
            </xsl:when>
        </xsl:choose>
    </xsl:template>

    <!-- Add the topConceptOf element to the right concepts -->
    <xsl:template match="rdf:RDF/rdf:Description" mode="apply-top-concepts">
        <xsl:param name="top-concept-id"/>
        <xsl:choose>
            <xsl:when test="@rdf:about=$top-concept-id">
                <xsl:copy>
                    <xsl:copy-of select="@*"/>
                    <skos:topConceptOf>
                        <xsl:attribute name="rdf:resource">
                            <xsl:value-of select="$vocabulary-id"/>
                        </xsl:attribute>
                    </skos:topConceptOf>
                    <xsl:copy-of select="node()"/>
                </xsl:copy>
            </xsl:when>
        </xsl:choose>
    </xsl:template>

    <!-- Add the skos:narrower element to the right concepts -->    
    <xsl:template match="rdf:RDF/rdf:Description" mode="apply-skos-narrower">
        <xsl:param name="this-concept-id"/>
        <xsl:param name="narrower-concept-id"/>
            <xsl:choose>
                <xsl:when test="@rdf:about=$this-concept-id">
                    <xsl:copy>
                        <xsl:copy-of select="@*|node()"/>
                        <skos:narrower>
                            <xsl:attribute name="rdf:resource">
                                <xsl:value-of select="$narrower-concept-id"/>
                            </xsl:attribute>
                        </skos:narrower>
                        <xsl:copy-of select="node()"/>
                    </xsl:copy>         
                </xsl:when>
            </xsl:choose>       
    </xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:0)

首先警告:你不应该使用像XSLT这样的纯XML处理工具来处理RDF-XML,除非别无选择。对于相同的底层RDF图,有许多等效的XML表示,使用理解图结构的正确RDF工具会更好。

那就是说...我认为你可以通过一个能让你通过skos:broader查找rdf:resource元素的密钥以更简单的方式实现你想要的。然后在您处理rdf:Description X的时候,以X作为对象来查找更宽的三元组,并创建相应的“#34”更小的&#34;逆。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" version="1.0"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:skos="http://www.w3.org/2004/02/skos/core#"
>
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:key name="broaderByObject" match="skos:broader" use="@rdf:resource" />

    <!-- identity template - copy everything as-is except for overrides -->
    <xsl:template match="@*|node()">
        <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
    </xsl:template>

    <xsl:template match="rdf:Description">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:for-each select="key('broaderByObject', @rdf:about)">
                <!-- the object of the narrower is the subject from the broader -->
                <skos:narrower rdf:resource="{../@rdf:about}" />
            </xsl:for-each>
            <xsl:apply-templates select="node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

同样的原则适用于顶级概念 - 添加密钥

<xsl:key name="topConByObject" match="skos:hasTopConcept" use="@rdf:resource" />

并查找创建反转的键

<xsl:if test="key('topConByObject', @rdf:about)">
    <skos:topConceptOf rdf:resource="{$vocabulary-id}" />
</xsl:if>