XSLT 中的依赖图遍历,用于复制 XML 模型的相关元素 [英] dependency graph traversal in XSLT for copying related elements of an XML model

查看:41
本文介绍了XSLT 中的依赖图遍历,用于复制 XML 模型的相关元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过解决以下问题来展示 XSL 对数据探索的强大功能:给定一个描述某种实体关系"模型的 xml 文件,并且对于该模型中由名称给出的一个实体(假设 XML 模式的一个属性用作标识符),我想要一个生成新 XML 的转换包含给定实体的模型,以及根据该给定实体的依赖关系的传递闭包"的所有亲属.

I want to demonstrate XSL powerfullness for data exploration by solving the following problem: Given an xml file that describes some kind of "entity-relashionship" model, and for one entity in that model given by a name (assuming an attribute of the XML schema is used as identifier), I want a transformation that produce a new XML model that contains the given entity, plus all of its relatives as per the "Transitive closure of the dependencies relationship" of that given entity.

例如,输入的 XML 模型是

For example, the input XML model is

<root>
    <!-- my model is made of 3 entities : leaf, composite and object -->
    <!-- the xml elements are <leaves>, <composites> and <objects> are just placeholders for these entities -->
    <!-- These placeholders are exepected to be in that order in the output as well as in the input (Schema constraints) -->
    <leaves>
        <!-- A, B, C are 3 types of different leaf nodes with their proper semantic in the model -->
        <A name="f1" others="oooo"/>
        <A name="f2" others="xxxx"/>
        <B name="f3" others="ssss"/>
        <C name="f4" others="gggg"/>    
    </leaves>
    <composites>
        <!-- composites containes only struct and union element -->
        <struct name="structB" others="yyyy">
            <!-- composite pattern, struct can embed struct in a tree-ish fashion -->
            <sRef name="s6" nameRef="structA"/>
            <!-- order of declaration does not matter !!! here in the XML, structA is not yet declared but file is valid -->
            <uRef name="u7" nameRef="unionX"/>
        </struct>
        <!-- union is another kind of composition -->
        <union name="unionX" others="rrrr">
            <vRef name="u3" nameRef="f3" others="jjjj">
            <vRef name="u4" nameRef="f2" others="pppp">
        </union>
        <struct name="structA" others="hhhh">
            <vRef name="v1" nameRef="f1" others="jjjj">
            <vRef name="v2" nameRef="f4" others="pppp">
        </struct>
    </composites>
    <objects>
        <object name="objB" others="tttt">
            <field name="field1" nameRef="unionX" others="qqqq"/>
            <field name="field2" nameRef="f2" others="cccc"/>
        </object>
        <object name="objC" others="nnnn">
            <field name="fieldX" nameRef="structB" others="uuuu"/>
            <field name="fieldY" nameRef="" others="mmmm"/>
        </object>
        <object name="objMain" others="nnnn">
            <field name="fieldY" nameRef="structA" others="mmmm"/>
            <field name="fieldY" nameRef="f3" others="mmmm"/>
            <field name="object4" nameRef="objB" others="wwwww"/>
        </object>
    </objects>
<root>

我想要一个转换,对于给定的名称,创建模型的副本,其中仅包含与该名称的元素相关的信息,以及 nameRef 属性描述的依赖项.

I would like a transformation that,for a given name, creates a copy of the model with only information related to the element of this name, and of its dependencies described by the nameRef attributes.

因此对于元素field1",输出将是

so for the element "field1" the output would be

<root>
    <leaves>
        <A name="f1" others="oooo"/>
    </leaves>
    <!-- composites and objects placeholders shall be copied even when no elements in the graph traversal -->
    <composites/>
    <objects/>
<root>

而对于objB",预期的输出是

whereas for "objB" the exepected output would be

<root>
    <leaves>
        <!-- element "f2" shall be copied only once in the output, althought the node is encountered twice in the traversal of "objB" tree :
            - "f2" is referenced under "field2" of "obj2"
            - "f2" is referenced under "u4" of "unionX" that is referencd under "field1" of "obj2"      
        -->
        <A name="f2" others="xxxx"/>
        <B name="f3" others="ssss"/>
    </leaves>
    <composites>
        <union name="unionX" others="rrrr">
            <vRef name="u3" nameRef="f3" others="jjjj">
            <vRef name="u4" nameRef="f2" others="pppp">
        </union>
    <composites>
    <objects>
        <object name="objB" others="tttt">
            <field name="field1" nameRef="unionX" others="qqqq"/>
            <field name="field2" nameRef="f2" others="cccc"/>
        </object>
    </objects>
<root>

依此类推.

从现在开始,我使用基本的 XSL 进行锻炼,但不是很满意,原因如下:

From now on, I workout on a basic XSL but not very satisfying for the following reasons :

  • 我的转换不是基于复制的身份规则"基础
  • 我的转换在遇到匹配实体时使用 xsl:copy-of,但这破坏了设计并违反了 XSD 架构
  • 输出文件不符合输入的 XML 模式定义,主要是因为 xsl:copy-of 违反了 XML 元素的遍历
  • 当一个实体在依赖关系的传递闭包中出现多次时,我的转换会在输出中产生重复的实体

对于好的和优雅的方式,我只有一些感觉和直觉".

I have only some feelings and "intuitions" about the good and elegant way to do it.

  • 从身份转换"模板开始,以尊重输入的 Xml Schema
  • 使用按键分组/排序
  • 为它实现了某种Muenchian Method"(实际上不确定,也许只是为了 XSLT 1.0)

为简化起见,您可以做出以下假设:

For simplification you can make the following assumptions:

  • 他们没有循环依赖的情况(可以实现树步行)
  • nameRef/name 由 XSD 中的键"交叉检查,以便输入中的引用正确
  • 要搜索的元素的输入参数名称"存在于输入 xml 模型中(尽管在这种情况下生成空"有效 xml 会很好)

空"的xml输出模型应该如下(由于模式限制)

the "empty" xml output model should be as follows (due to schema constraints)

<root>
    <leaves/>
    <composites/>
    <objects/>
<root> 

完成:我目前使用的xslt处理器是Saxon XSLT proc,XSLT的版本是2.0谢谢你的帮助...我不会给你我不引以为豪的 xsl,但如果它看起来有帮助,我会......

To complete : the xslt processor I am currently using is Saxon XSLT proc with and the version of XSLT is 2.0 Thanks for helping ... I don't give you the xsl that I am not proud of, but if it appears helpfull, I will ...

推荐答案

我试图实现一种转换,对于给定的名称,创建模型的副本,其中仅包含与该名称的元素相关的信息,并且https://xsltfiddle.liberty-development.net/gWEamLs/6:

I tried to implement "a transformation that,for a given name, creates a copy of the model with only information related to the element of this name, and of its dependencies described by the nameRef attributes" at https://xsltfiddle.liberty-development.net/gWEamLs/6:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="start-name" as="xs:string">objB</xsl:param>

  <xsl:key name="name-ref" match="*[@name]" use="@name"/>

  <xsl:function name="mf:traverse" as="element()*">
      <xsl:param name="start" as="element()?"/>
      <xsl:sequence select="$start, $start/*, $start/*[@nameRef]!key('name-ref', @nameRef, root(.))!mf:traverse(.)"/>
  </xsl:function>

  <xsl:param name="start-element" as="element()?" select="key('name-ref', $start-name)"/>

  <xsl:variable name="named-elements" select="mf:traverse($start-element)"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="*[@name and not(. intersect $named-elements)]"/>

</xsl:stylesheet>

基于键和递归函数,代码首先"将相关元素计算为全局变量中的元素节点序列,然后然后"通过 <xsl:mode on 声明性地设置身份转换-no-match="shallow-copy"/> 只是通过一个空模板扩展那些具有 name 属性但未被递归函数发现为相关的元素到开始元素,确保不会将任何不相关的元素复制到输出中.

Based on a key and a recursive function the code "first" computes the related elements as a sequence of element nodes in a global variable and "then" the identity transformation set up declaratively by <xsl:mode on-no-match="shallow-copy"/> just gets extended by an empty template for those elements having a name attribute but not having been found by the recursive function as being related to the start element, ensuring any not related elements that way don't get copied to the output.

这篇关于XSLT 中的依赖图遍历,用于复制 XML 模型的相关元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆