2015-02-24 129 views
0

如果可能的话,我需要编写转换与此类似生成ID系统XSL

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

的XML语法到这样

<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> 

我实现目标格式的格式的XSL文件有点复杂,但我无法控制它。

我已成功编写XSL以使用模板模式正确转换大部分XML标记。即。

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

不过,我一直在尝试使用<的xsl:数>或其他一些技巧来生成ID的正确,但收效甚微。

目标格式对id有两个约束:每个id属性,无管理<元素>,名称必须是唯一的。这些ID一旦被分类,必须是顺序的,但它们可以以目标格式的任何顺序出现,即(1,2,3,4,5)和(5,2,3,1,4)都可以接受,但( 1,2,4,5,6)不是。

有什么办法可以通过XSL来实现吗?

+0

您确定您确实需要第二个约束吗?将输出节点链接到**不存在于输入**中的其他输出节点将会非常困难(并且应该正确地问你为什么还需要*)。 – 2015-02-24 20:14:14

+0

不幸的是,我确实需要第二个约束。但是,假设我没有,是否有办法只使用XSL来满足第一个约束? – spectacularbob 2015-02-24 20:17:33

+0

还有一种方法可以满足第二个约束条件。真正的问题是你愿意付出多少努力。你和那些试图帮助你的人。就我而言,我发现这项任务毫无兴趣,因为我看不出这对任何事情有什么帮助。你的头衔说的是主/外键;除了这些书已经有独特和永久的ISBN这一事实之外,很明显Books(你称之为book_definitions)是父表,所有其他表都应该链接到它,而不是一个级联中的彼此。 – 2015-02-24 20:31:55

回答

1

虽然我只注意到伊恩·罗伯茨已经解释过这种方法,我已经是要写这一个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> 

当应用到你的输入XML生成输出

<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>3</book_definition_id> 
     <book_metadata_id>5</book_metadata_id> 
     <title>Your Book</title> 
     </book_instance> 
    </book_instances> 
    </medialist> 
</library> 

由于不清楚输入XML是否包含多个media元素 - 例如然后应该以id 8开始的下一个建筑物 - 我使用数字作为参数而不是仅添加1.
请注意,此模板不适用于第二个media元素 - 这将仅以2开始,作为id的值 - 如果实际输入XML包含多个建筑物/ media元素,则必须相应地进行调整。
对于书中的定义,id是当前图书的位置之和参数current的价值:

<book_definition id="{(position() + $current)}" /> 

元数据id是当前图书的位置的总和,所有书籍当前/父media元素和current

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

和书实例ID,考虑到元数据之前生成的ID,是当前的书,current的位置的父的所有书籍的总和media元素* 2:

<book_instance id="{(position() + 2*count(parent::media/book) + $current)}"> 
1

在我看来,既然(除了建筑物),你总是为每个不同的“种类”的节点生成一本书ID,你可以通过根据公式生成它们来保证独特和顺序的ID。如果你有N个书,那么你可以“法令”是

  • 建设始终是ID 1
  • book_definition的书m是始终1+m(因此运行从2个至N + 1)
  • 的对于本书米的元数据是(N+1)+m
  • 实例为(2N+1)+m

如果按照这个方案,随处都可以简单地计算出合适的交叉引用book_definition_id等,不需要查找表。