2015-06-24 3 views
0

Я должен обновить XML с помощью XSLT.XSLT: создать новый уникальный идентификатор int для элемента

Мой предыдущий элемент XML имеет некоторый элемент с атрибутом Id с значением int. Некоторый элемент не имеет этого Id, поскольку на них нельзя ссылаться ни на один другой элемент.

XML Пример:

<Object Id="12359" Type="TypeX"> 
<Object Type="TypeA"> 
    <SomeOtherObject Id="112" Type="TypeV"/> 
</Object> 
<SomeOtherOtherObject Id="1596" Type="TypeM"/> 
</Object> 

Для одного конкретного пункта (который можно легко управлять, чтобы выбрать с запросом XPATH, я хочу, чтобы создать новый идентификатор, который не используется какой-либо другой элемент

.

Может ли это быть сделано с помощью XSLT

у меня уже есть ключ:

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

И я могу выбрать элемент, который имеет недостающий свойство как это:

<xsl:template match="*[@Type='TypeA']"> 

Это будет выполняться с помощью C# приложения, но я хотел бы избежать любой ценой любой C# код.

+0

должен ли он быть целым числом XSLT имеет идентификатор генерировать-'()' функцию, чтобы присвоить уникальный идентификатор строки для каждого узла –

+0

Да, это. модель, которая в настоящее время сериализована в XML и в базе данных, и отправляется на некоторые жесткие это устройства, нет возможности изменить тип этого идентификатора. – J4N

+1

Вы действительно должны сказать нам, является ли это XSLT 1.0 или 2.0. –

ответ

0

Вы не можете изменять переменные в XSLT, поэтому установка глобальной переменной и увеличение ее по мере того, как вы собираетесь отслеживать следующий уникальный идентификатор, невозможно.

Но вы могли бы сделать это:

  • выбрать максимальный идентификатор в документе:

    <xsl:variable name="max-id" select="//@Id[not(. &lt; //@Id)]" /> 
    
  • создать разделенный запятыми список уникальных идентификаторов элементов (с помощью generate-id()) и именованный шаблон:

    <xsl:variable name="missing-list"> 
        <xsl:call-template name="list-ids"> 
        <xsl:with-param name="nodes" select="//*[not(@Id)]" /> 
        </xsl:call-tempalte> 
    </xsl:variable> 
    
    <!-- and --> 
    
    <xsl:template name="list-ids"> 
        <xsl:param name="nodes" /> 
        <xsl:for-each select="$nodes"> 
        <xsl:value-of select="concat(generate-id(), ',')" /> 
        </xsl:for-each> 
    </xsl:template> 
    
  • Используйте это в качестве контрольной точки. Для любого заданного элемента (который не имеет @Id), новый уникальный идентификатор станет $max-id плюс свою позицию в этом списке (вы можете получить, что с substring-before($missing-list, generate-id()), чтобы получить позицию мы считаем запятые:

    <xsl:variable name="pos" select=" 
        string-length($preceding-ids) 
        - string-length(translate($preceding-ids, ',', '')) 
    "/> 
    
    <xsl:attribute name="Id"> 
        <xsl:value-of select="$max-id + $pos + 1" /> 
    </xsl:attribute> 
    

Так, вместе взятое это выглядит следующим образом:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output encoding="UTF-8" indent="yes" /> 

    <xsl:variable name="max-id" select="//@Id[not(. &lt; //@Id)]" /> 

    <xsl:variable name="missing-list"> 
     <xsl:call-template name="list-ids"> 
     <xsl:with-param name="nodes" select="//*[not(@Id)]" /> 
     </xsl:call-template> 
    </xsl:variable> 

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

    <xsl:template match="*[not(@Id)]"> 
     <xsl:copy> 
     <xsl:apply-templates select="@*" /> 

     <xsl:variable name="preceding-ids" select=" 
      substring-before($missing-list, generate-id()) 
     "/> 
     <xsl:variable name="pos" select=" 
      string-length($preceding-ids) 
      - string-length(translate($preceding-ids, ',', '')) 
     "/> 

     <xsl:attribute name="Id"> 
      <xsl:value-of select="$max-id + $pos + 1" /> 
     </xsl:attribute> 

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

    <xsl:template name="list-ids"> 
     <xsl:param name="nodes" /> 
     <xsl:for-each select="$nodes"> 
     <xsl:value-of select="concat(generate-id(), ',')" /> 
     </xsl:for-each> 
    </xsl:template>   
</xsl:transform> 
+0

Я вижу вашу точку зрения. Я думаю, что в большинстве случаев это сработает. Проблема, которую я могу иметь, заключается в том, что мои идентификаторы, вероятно, не являются непрерывными, но случайными (не мой выбор: /), поскольку у меня достаточно Id после максимального использования Id, это должно быть хорошо, но я не уверен, что я может рассчитывать на это :( – J4N

+0

@ J4N Ну, мое предположение, конечно, заключалось в том, что ваши идентификаторы не ограничивались бы максимумом, и переполнение было маловероятным в вашем случае использования. – Tomalak

+0

Хорошо спасибо. Вы правы, это очень маловероятно ,Просто с законом Мерфи, и поскольку мы можем потерять важные данные, если это пойдет не так, я пытаюсь найти лучший способ. Но хорошо, что я знаю, что добавить этот идентификатор будет не так много. Один вопрос, можно ли закодировать в C# тег XSLT? – J4N

Смежные вопросы