XSLT:生成整数ID并在输入上使用字符串键引用它们

XSLT:生成整数ID并在输入上使用字符串键引用它们,xslt,reference,integer,key,generated,Xslt,Reference,Integer,Key,Generated,我需要为产品生成整数ID,然后通过输出中的整数ID引用相关产品。在输入上,我有表示这种关系的字符串键。谢谢你的帮助 输入: <root> <products> <product> <!-- a unique string key of this node between the other product nodes --> <stringKey>AppleRef</stringKey>

我需要为产品生成整数ID,然后通过输出中的整数ID引用相关产品。在输入上,我有表示这种关系的字符串键。谢谢你的帮助

输入:

<root>
  <products>
    <product>
      <!-- a unique string key of this node between the other product nodes -->
      <stringKey>AppleRef</stringKey>
      <Name>Apple</Name>
      <relatedProducts>
        <!-- a reference to product/StringKey of Orange -->
        <relatedProductStringKey>OrangeRef</relatedProductStringKey>
        <!-- other related products may follow -->
      </relatedProducts>
    </product>
    <product>
      <stringKey>OrangeRef</stringKey>
      <Name>Orange</Name>
      <relatedProducts>
        <relatedProductStringKey>AppleRef</relatedProductStringKey>
      </relatedProducts>
    </product>
  </products>
</root>

阿普雷夫
苹果
橘子
橘子
橙色
阿普雷夫
预期产出:

<root>
  <products>
    <P>
      <ProductInfo>
        <!-- a unique integer ID of this node between the other ProductsInfo nodes -->
        <ProductID>0</ProductID>
        <ProductRef>AppleRef</ProductRef>
        <ProductName>Apple</ProductName>
      </ProductInfo>
      <R>
        <ProductRelatedInfo>

          <!-- a unique integer ID of this node between the other ProductRelatedInfo nodes -->
          <RelatedID>0</RelatedID>

          <!-- a reference to ProductInfo/ProductID of Orange -->
          <RelatedProductID>1</RelatedProductID>

        </ProductRelatedInfo>
        <!-- other related products may follow -->

      </R>
    </P>
    <P>
      <ProductInfo>
        <ProductID>1</ProductID>
        <ProductRef>OrangeRef</ProductRef>
        <ProductName>Orange</ProductName>
      </ProductInfo>
      <R>
        <ProductRelatedInfo>
          <RelatedID>1</RelatedID>
          <RelatedProductID>0</RelatedProductID>
        </ProductRelatedInfo>
      </R>
    </P>
  </products>
</root>

0 阿普雷夫 苹果 0 1.

1. 橘子 橙色 1. 0


要在XSLT中获取整数ID,可以使用文档中节点的位置,这可以通过计算其前面的节点来获得

以下样式表将生成所需的结果:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output indent="yes"/>

    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>

    <!-- match product node -->
    <xsl:template match="product">
        <P>
            <ProductInfo>
                <ProductID>
                    <!-- count preceding-sibling products -->
                    <xsl:value-of select="count(preceding-sibling::product)"/>
                </ProductID>
                <ProductRef>
                    <xsl:value-of select="stringKey"/>
                </ProductRef>
                <ProductName>
                    <xsl:value-of select="Name"/>
                </ProductName>
            </ProductInfo>
            <xsl:apply-templates select="relatedProducts"/>
        </P>
    </xsl:template>

    <xsl:template match="relatedProducts">
        <R>
            <xsl:for-each select="relatedProductStringKey">
                <!-- apply on product that has a matching stringkey -->
                <xsl:apply-templates select="/root/products/product[stringKey=current()]" mode="related">
                    <!-- 
                        RelatedID will be unique within each relatedProducts node, 
                        if you want this to be unique across the document use preceding:: instead 
                    -->
                    <xsl:with-param name="RelatedID" select="count(preceding-sibling::relatedProductStringKey)"/>
                </xsl:apply-templates>
            </xsl:for-each>
        </R>
    </xsl:template>

    <!-- match product node for related products -->
    <xsl:template match="product" mode="related">
        <xsl:param name="RelatedID"/>
        <ProductRelatedInfo>

            <!-- a unique integer ID of this node between the other ProductRelatedInfo nodes -->
            <RelatedID>
                <xsl:value-of select="$RelatedID"/>
            </RelatedID>

            <!-- a reference to ProductInfo/ProductID of Orange -->
            <RelatedProductID>
                <!-- count preceding-sibling products again -->
                <xsl:value-of select="count(preceding-sibling::product)"/>
            </RelatedProductID>

        </ProductRelatedInfo>
    </xsl:template>

</xsl:stylesheet>


使用键很容易做到这一点。例如,以下样式表:

XSLT1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="product" match="product" use="stringKey" />

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="stringKey">
    <ProductID><xsl:value-of select="count(../preceding-sibling::product)"/></ProductID>
    <ProductRef><xsl:value-of select="."/></ProductRef>
</xsl:template>

<xsl:template match="relatedProductStringKey">
    <RelatedProductID><xsl:value-of select="count(key('product', .)/preceding-sibling::product)"/></RelatedProductID>
</xsl:template>

</xsl:stylesheet>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="product" match="product" use="stringKey" />

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="stringKey">
    <ProductID><xsl:value-of select="generate-id(..)"/></ProductID>
    <ProductRef><xsl:value-of select="."/></ProductRef>
</xsl:template>

<xsl:template match="relatedProductStringKey">
    <RelatedProductID><xsl:value-of select="generate-id(key('product', .))"/></RelatedProductID>
</xsl:template>

</xsl:stylesheet>

应用于输入时,将返回:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <products>
      <product>
         <ProductID>0</ProductID>
         <ProductRef>AppleRef</ProductRef>
         <Name>Apple</Name>
         <relatedProducts>
            <RelatedProductID>1</RelatedProductID>
         </relatedProducts>
      </product>
      <product>
         <ProductID>1</ProductID>
         <ProductRef>OrangeRef</ProductRef>
         <Name>Orange</Name>
         <relatedProducts>
            <RelatedProductID>0</RelatedProductID>
         </relatedProducts>
      </product>
   </products>
</root>

0
阿普雷夫
苹果
1.
1.
橘子
橙色
0
如果您喜欢无意义但不一定是数字的ID,您可能会喜欢更简单的:

XSLT1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="product" match="product" use="stringKey" />

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="stringKey">
    <ProductID><xsl:value-of select="count(../preceding-sibling::product)"/></ProductID>
    <ProductRef><xsl:value-of select="."/></ProductRef>
</xsl:template>

<xsl:template match="relatedProductStringKey">
    <RelatedProductID><xsl:value-of select="count(key('product', .)/preceding-sibling::product)"/></RelatedProductID>
</xsl:template>

</xsl:stylesheet>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="product" match="product" use="stringKey" />

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="stringKey">
    <ProductID><xsl:value-of select="generate-id(..)"/></ProductID>
    <ProductRef><xsl:value-of select="."/></ProductRef>
</xsl:template>

<xsl:template match="relatedProductStringKey">
    <RelatedProductID><xsl:value-of select="generate-id(key('product', .))"/></RelatedProductID>
</xsl:template>

</xsl:stylesheet>

具体结果取决于处理器,例如,Saxon可能返回:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <products>
      <product>
         <ProductID>d0e3</ProductID>
         <ProductRef>AppleRef</ProductRef>
         <Name>Apple</Name>
         <relatedProducts>
            <RelatedProductID>d0e11</RelatedProductID>
         </relatedProducts>
      </product>
      <product>
         <ProductID>d0e11</ProductID>
         <ProductRef>OrangeRef</ProductRef>
         <Name>Orange</Name>
         <relatedProducts>
            <RelatedProductID>d0e3</RelatedProductID>
         </relatedProducts>
      </product>
   </products>
</root>

d0e3
阿普雷夫
苹果
d0e11
d0e11
橘子
橙色
d0e3
而libxslt将生成如下内容:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <products>
    <product>
      <ProductID>idp116928</ProductID>
      <ProductRef>AppleRef</ProductRef>
      <Name>Apple</Name>
      <relatedProducts>
        <RelatedProductID>idp1506944</RelatedProductID>
      </relatedProducts>
    </product>
    <product>
      <ProductID>idp1506944</ProductID>
      <ProductRef>OrangeRef</ProductRef>
      <Name>Orange</Name>
      <relatedProducts>
        <RelatedProductID>idp116928</RelatedProductID>
      </relatedProducts>
    </product>
  </products>

idp116928
阿普雷夫
苹果
idp1506944
idp1506944
橘子
橙色
idp116928

为什么必须用唯一的数字字符串(即整数)替换唯一的字符串?@michael.hor257k,因为外部应用程序需要输出格式。我需要将从一个应用程序导出的产品目录转换为将数据导入另一个应用程序的格式。+1。谢谢你的帮助,托比亚斯。我应用了michael.hor257k的解决方案,因为它对我来说更具可读性。我是XSLT新手,所以我可能错了。我认为你的解决方案对参考很有用,我以后可能会把它应用到这个或类似的问题上。如果您或其他人知道此解决方案比我选择的解决方案有任何优势,请告诉我。