Xml 用XSL生成id系统

Xml 用XSL生成id系统,xml,xslt,Xml,Xslt,如果可能的话,我需要编写一个XSL文件来转换与此类似的XML语法 <media address="1234 A St."> <book title="My Book" isbn="1324-1123-1456-1566" /> <book title="Your Book" isbn="1232-1123-1456-1566" /> </media> 变成这样的格式 <library> <informati

如果可能的话,我需要编写一个XSL文件来转换与此类似的XML语法

<media address="1234 A St.">
  <book title="My Book" isbn="1324-1123-1456-1566" />
  <book title="Your Book" isbn="1232-1123-1456-1566" />
</media>

变成这样的格式

<library>

    <information>
       <building id="1">
           <address>1234 A St.</address>
       </building>
    </information>

    <medialist>
        <book_definitions>
            <book_definition id="2" />
            <book_definition id="3" />
        </book_definitions>
        <book_metadata>
           <metadata id="4">
               <isbn>1324-1123-1456-1566</isbn>
               <book_definition_id>2</book_definition_id>
           </metadata>
           <metadata id="5">
               <isbn>1232-1123-1456-1566</isbn>
               <book_definition_id>3</book_definition_id>
           </metadata>
        </book_metadata>
        <book_instances>
            <book_instance id="6">
                <book_definition_id>2</book_definition_id>
                <book_metadata_id>4</book_metadata_id>
                <title>My Book</title>
            </book_instance>
            <book_instance id="7">
                <book_definition_id>2</book_definition_id>
                <book_metadata_id>5</book_metadata_id>
                <title>Your Book</title>
            </book_instance>
        </book_instances>
    </medialist>
</library>

1234 A街。
1324-1123-1456-1566
2.
1232-1123-1456-1566
3.
2.
4.
我的书
2.
5.
你的书
我意识到目标格式有点复杂,但我无法控制它

我已经成功地编写了XSL,以使用模板模式正确地转换大多数XML标记。即

<xsl:template match="/media/book" mode="definitions">
<xsl:template match="/media/book" mode="metadata">
<xsl:template match="/media/book" mode="instance">

然而,我一直在尝试使用或其他一些技巧来正确生成id,但收效甚微

目标格式对id有两个约束:每个id属性(无规则)的名称必须是唯一的。一旦排序,ID必须是连续的,但它们可以以目标格式的任何顺序出现,即(1,2,3,4,5)和(5,2,3,1,4)都可以接受,但(1,2,4,5,6)不可以

有没有办法通过XSL实现这一点?

在我看来,因为(除了建筑之外),您总是为每种不同的“类型”节点为每本书生成一个ID,所以您可以通过根据公式生成ID来保证唯一和连续的ID。如果你有N本书,那么你可以“命令”它

  • 该建筑始终为id 1
  • 书籍m的
    book\u定义
    始终是
    1+m
    (因此从2运行到N+1)
  • 图书m的元数据是
    (N+1)+m
  • 实例是
    (2N+1)+m

如果您在任何地方都遵循此方案,您只需计算适当的交叉引用
图书定义\u id
等,而无需查找表。

虽然我刚刚注意到Ian Roberts已经解释了此方法,但我已经准备为此编写XSLT,因此我将发布它-遵循XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*" />
    <xsl:template match="/">
        <library>
            <xsl:apply-templates />
        </library>
    </xsl:template>
    <xsl:template match="media">
        <xsl:variable name="current">
            <xsl:number />
        </xsl:variable>
        <information>
            <building>
                <xsl:attribute name="id">
                    <xsl:value-of select="$current" />
                </xsl:attribute>
                <address>
                    <xsl:value-of select="@address" />
                </address>
            </building>
        </information>
        <medialist>
            <book_definitions>
                <xsl:apply-templates mode="definition">
                    <xsl:with-param name="current">
                        <xsl:value-of select="$current" />
                    </xsl:with-param>
                </xsl:apply-templates>
            </book_definitions>
            <book_metadata>
                <xsl:apply-templates mode="metadata">
                    <xsl:with-param name="current">
                        <xsl:value-of select="$current" />
                    </xsl:with-param>
                </xsl:apply-templates>
            </book_metadata>
            <book_instances>
                <xsl:apply-templates mode="instances">
                    <xsl:with-param name="current">
                        <xsl:value-of select="$current" />
                    </xsl:with-param>
                </xsl:apply-templates>
            </book_instances>
        </medialist>
    </xsl:template>
    <xsl:template match="book" mode="definition">
        <xsl:param name="current" />
        <book_definition id="{(position() + $current)}" />
    </xsl:template>
    <xsl:template match="book" mode="metadata">
        <xsl:param name="current" />
        <metadata id="{(position() + $current + count(parent::media/book))}">
            <isbn>
                <xsl:value-of select="@isbn" />
            </isbn>
            <book_definition_id>
                <xsl:value-of select="position() + $current" />
            </book_definition_id>
        </metadata>
    </xsl:template>
    <xsl:template match="book" mode="instances">
        <xsl:param name="current" />
        <book_instance id="{(position() + 2*count(parent::media/book) + $current)}">
            <book_definition_id>
                <xsl:value-of select="position() + $current" />
            </book_definition_id>
            <book_metadata_id>
                <xsl:value-of select="position() + $current + count(parent::media/book)" />
            </book_metadata_id>
            <title>
                <xsl:value-of select="@title" />
            </title>
        </book_instance>
    </xsl:template>
</xsl:transform>
元数据id是当前书籍、当前/父
媒体
元素的所有书籍和
当前
元素的位置的总和:

<book_definition id="{(position() + $current)}" /> 
<metadata id="{(position() + $current + count(parent::media/book))}">

你确定你真的需要第二个约束吗?要使输出节点链接到输入中不存在的其他输出节点将非常困难(人们应该正确地问,为什么您也需要这样做)。不幸的是,我确实需要第二个约束。然而,假设我没有这样做,有没有一种方法可以使用XSL只满足第一个约束?还有一种方法可以满足第二个约束。真正的问题是你愿意为此付出多少努力。你和那些试图帮助你的人。一、 首先,我觉得这项任务没有意思,因为我看不出这对任何事情都有什么帮助。您的标题谈到主键/外键;好吧,除了这些书已经有一个唯一且永久的ISBN这一事实之外,很明显,books(你称之为book_definitions)是父表,所有其他表都应该链接到它,而不是以级联方式彼此链接。也许你对标题的看法是正确的。我改了。至于示例XML,我不能发布实际的格式,因为它包含专有信息,我选择使用一些常见的东西来模拟该格式。不幸的是,我无法控制目标格式,必须符合他们不寻常的标准。请相信这些要求与我描述的一样。至于你的不感兴趣,谢谢你的评论,但我非常感谢任何愿意进一步帮助我的人。
<metadata id="{(position() + $current + count(parent::media/book))}">
<book_instance id="{(position() + 2*count(parent::media/book) + $current)}">