2010-12-03 3 views
1

Отредактировано в слабой попытке уточнить. Система преобразует XML в другой XML через XSL-процессор.XSL: есть ли быстрая альтернатива использованию переменной-в-предиката?

Я делаю некоторые вещи правила XSL для машины с плагинами. Карты будут поставлять свои собственные правила XSL на главный хост, что, в свою очередь, сопоставит их с одним супер-XSL-файлом, который будет обрабатываться сам по себе, а также отправлен веб-браузерам, которые на него набрали HTTP'd. Браузер используется для установки элементов конфигурации для машины, а XSL - для изменения и/или скрытия и/или отображения некоторых из XML. Чтобы упростить мой запрос здесь, я придумал небольшой пример.

Когда пользователь настраивает элемент типа B (выбор из нескольких, таких как A, B, C, ...), то следующие два элемента также должны быть изменены (в некотором роде). В реальной сделке есть атрибут «скрытый», установленный в true или false, а также дочерние элементы, которые установлены. Следующие два элемента в реальной вещи должны быть скрыты, а также элементы ребенка изменены.

Когда пользователь меняет элемент из типа B, чтобы сказать тип A, мне нужно выяснить, какие другие узлы должны иметь свой «скрытый» атрибут, равный false. Пользователь будет изменять дочерние элементы по своему усмотрению.

Все это «круговое» и упорядоченное, поэтому, если узел настроен на тип B, и это последний узел (без последующего сиблинга), то затронутые узлы являются первыми в наборе. (В терминах XPath, если узел [4] является типом B, то узлы [1] и [2] должны быть скрыты и изменены).

Так, для моего примера здесь, я в качестве входного XML:

<topline> 
    <midline type="A" name="mid1" hidden="false"><source name="off"/></midline> 
    <midline type="B" name="mid2" hidden="false"><source name="input 1"/></midline> 
    <midline type="A" name="mid3" hidden="false"><source name="off"/></midline> 
    <midline type="A" name="mid4" hidden="false"><source name="off"/></midline> 
</topline> 

и XSL изменит это:

<topline> 
    <midline type="A" name="mid1" hidden="false"><source name="off"/></midline> 
    <midline type="B" name="mid2" hidden="false"><source name="input 1"/></midline> 
    <midline type="A" name="mid3" hidden="true"><source name="input 1"/></midline> 
    <midline type="A" name="mid4" hidden="true"><source name="input 1"/></midline> 
</topline> 

Теперь, если пользователь изменяет свое мнение, а также изменения MID2 быть типа А:

<topline> 
    <midline type="A" name="mid1" hidden="false"><source name="off"/></midline> 
    <midline type="A" name="mid2" hidden="false"><source name="input 1"/></midline> 
    <midline type="A" name="mid3" hidden="true"><source name="input 1"/></midline> 
    <midline type="A" name="mid4" hidden="true"><source name="input 1"/></midline> 
</topline> 

то XSL будет отобразить циркуляр следующий сибсов MID2, так что результат Shou ld be:

<topline> 
    <midline type="A" name="mid1" hidden="false"><source name="off"/></midline> 
    <midline type="A" name="mid2" hidden="false"><source name="input 1"/></midline> 
    <midline type="A" name="mid3" hidden="false"><source name="input 1"/></midline> 
    <midline type="A" name="mid4" hidden="false"><source name="input 1"/></midline> 
</topline> 

Это второй шаг, с которым я борюсь. То, что я сделал, чтобы решить это, для меня, довольно уродливое, но, возможно, неизбежное, учитывая то, что я пытаюсь достичь, на самом деле не XSL.

Что я приземлился вверх делает:

<xsl:for-each select="topline"> 
    <xsl:for-each select="midline"> 
    <xsl:variable name="masterPosition" select="position()"/> 
    <xsl:choose> 
     <xsl:when test="@type='B'> 
     hide the next two nodes. This is easy: 
      translate($masterPosition, '1234', '2341') 
     works nicely. 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:variable name="prior1" select="translate(masterPosition, '1234', '4123')"/> 
      <xsl:variable name="test1" select="../midline[$prior1]/source[1]/@name='off'"/> 
      this second line doesn't work: I only get the first node, always. 
      So instead I have 
      <xsl:variable name="test2"> 
       <xsl:choice> 
        <xsl:when test="$masterPosition='1'"><xsl:value-of select="../midline[4]/source"/></xsl:when> 
        and so on for the other masterPositions 
       </xsl:choice> 
      </xsl:variable> 
      and this is repeated for a few other variables, one each for each relevant 
      prior position and for the fields I need to change. I then use these 
      variables to change the XML - there's something in the main machine's 
      processing to enable this, I believe it is non-standard, so please ignore: 
      (At least it doesn't run against Xalan). 
      <set key={$test2}/@hidden, value="false")/>    
     </xsl:otherwise> 
    </xsl:choose> 
    <xsl:for-each> 
</xsl:for-each> 

Есть ли более элегантный способ сделать это, что вы можете думать? Если нет, не волнуйтесь, я считаю, что мой хак будет работать, а также не должен потреблять слишком много MIPS.

Я не могу использовать <xsl:key>, так как наша система не справляется: у нас есть несколько источников XSL, которые объединяются в один, а скрипт colating (из моего контроля) просто не понимает <xsl:key>, поэтому, если есть решение с использованием ключей, я не могу его использовать.

Благодаря Richard

+0

Вам необходимо убедиться, что вы правильно отмечаете все теги как код в редакторе уценок. Похоже, что в «Что я хочу делать» есть теги, которые отсутствуют, по крайней мере, я не понимаю, чего вы хотите достичь. – Lucero

+0

Это странно. Форматирование не очень велико, но (для меня, но потом я его написал) кажется достаточно ясным: сравните первый XML со вторым: исходные имена меняются для «mid1» и «mid4», потому что они предшествуют круговым образом , "mid2". Мне нужен способ, чтобы натолкнуться на узел «mid4», определить, связано ли это с «mid2», потому что при обработке «mid2» он изменил «mid4». Если это так, я оставляю это в покое, иначе у меня есть другие вещи, которые мне нужно сделать с этим («это», как мой пример). Надеюсь, это поможет, это звучит немного бессвязно :-) – Richard

+0

Хороший вопрос, +1. См. Мой ответ для полного решения для обращения от типа B к типу-A. :) –

ответ

1

Вот один из способов сделать то, что вы хотите, без ключей, на основе сопоставления шаблона:

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

<!-- <midline>s that have two preceding siblings --> 
<xsl:template match="midline[@type='A'][count(preceding-sibling::midline) &gt; 1]"> 
    <xsl:apply-templates select="." mode="source"> 
    <xsl:with-param name="circular" select=" 
     preceding-sibling::midline[position() &lt;= 2] 
    " /> 
    </xsl:apply-templates> 
</xsl:template> 

<!-- <midline>s that have one preceding sibling --> 
<xsl:template match="midline[@type='A'][count(preceding-sibling::midline) = 1]"> 
    <xsl:apply-templates select="." mode="source"> 
    <xsl:with-param name="circular" select=" 
     (preceding-sibling::midline|../midline[last()]) 
    " /> 
    </xsl:apply-templates> 
</xsl:template> 

<!-- <midline>s that have no preceding sibling --> 
<xsl:template match="midline[@type='A'][count(preceding-sibling::midline) = 0]"> 
    <xsl:apply-templates select="." mode="source"> 
    <xsl:with-param name="circular" select=" 
     ../midline[position() &gt; last() - 2] 
    " /> 
    </xsl:apply-templates> 
</xsl:template> 

<!-- this template creates a new node with the wanted source --> 
<xsl:template match="midline" mode="source"> 
    <xsl:param name="circular" select="." /> 
    <xsl:variable name="prevB" select="$circular[@type = 'B' and not(@mode = off)]" /> 
    <xsl:copy> 
    <xsl:copy-of select="@*" /> 
    <xsl:attribute name="hidden"> 
     <xsl:value-of select="boolean($prevB)" /> 
    </xsl:attribute> 
    <xsl:choose> 
     <xsl:when test="$prevB"> 
     <xsl:copy-of select="$prevB/source" /> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:copy-of select="source" /> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:copy> 
</xsl:template> 

Для вашего ввода пробы, результат будет:

<topline> 
    <midline type="A" name="mid1" hidden="false"><source name="off"/></midline> 
    <midline type="B" name="mid2" hidden="false"><source name="input 1"/></midline> 
    <midline type="A" name="mid3" hidden="true"><source name="input 1"/></midline> 
    <midline type="A" name="mid4" hidden="true"><source name="input 1"/></midline> 
</topline> 

Обратите внимание, что ваше описание противоречит вашему образцу вывода - это то, что вы получите, строго следуя вашему описанию, unles Я вас неправильно понял.

<xsl:with-param> Используется для передачи в двух узлах, которые являются «круговыми предшествующими братьями и сестрами» (или пустым набором узлов в случае узлов @type=B').

Этот шаблон <xsl:template match="midline" mode="source"> использует этот параметр: если он есть, он проверяет ваше состояние (то есть один из них - @type='B', и это не @mode='off').

Если такой узел существует, он копирует его <source>, иначе он копирует оригинал <source>.

+0

Привет, Томалак. Большое вам спасибо, я посмотрю, смогу ли я применить это, мне еще нужно правильно понять соответствие шаблонов. Я также не думаю, что я сформулировал свой вопрос очень хорошо: мне нужно разобраться в обратном: это означает, что «mid4» установлен на «ввод 1» из-за «середины 2», являющегося типом B, или потому, что входной XML имел это значение уже. Если первое, я оставляю его в покое, иначе я могу его изменить. (Конечно, «вход 1» может быть одним из многих значений). Я перевариваю ваш ответ, чтобы узнать, есть ли у него решение, в котором я нуждаюсь. Спасибо, что нашли время, Ричард. – Richard

+0

@ Рихард: Я изменил свой код тем временем. Боюсь, я все еще не понимаю 100%, когда изменения должны применяться. Измените свой вопрос и создайте однозначное описание того, какие значения вы хотите изменить или сохранить на основе каких критериев. * (возможно, когда вы поняли мой код, вам проще указать, где я неправильно интерпретирую ваше описание) * – Tomalak

+0

Привет, Томалак. Еще раз спасибо: я отредактировал свой запрос, но я понимаю ваше решение и соответствующим образом переработаю свой материал. Я не очень хорошо использовал материал Xpath, который вы сделали. Вернемся к мозгу. С уважением Ричард – Richard

1

Чтобы сделать обратное преобразование, вы хотите это:

когда это преобразование применяется на следующий (при условии) XML, где пользователь только изменил type='B' в type='A':

<topline> 
    <midline type="A" name="mid1" hidden="false"> 
     <source name="off"/> 
    </midline> 
    <midline type="A" name="mid2" hidden="false"> 
     <source name="input 1"/> 
    </midline> 
    <midline type="A" name="mid3" hidden="true"> 
     <source name="input 1"/> 
    </midline> 
    <midline type="A" name="mid4" hidden="true"> 
     <source name="input 1"/> 
    </midline> 
</topline> 

в изнуренный Ted, правильный результат получается (hidden="false" устанавливается для экс-B-типа следующие два круглых братьев и сестер):

<topline> 
    <midline type="A" name="mid1" hidden="false"> 
     <source name="off"/> 
    </midline> 
    <midline type="A" name="mid2" hidden="false"> 
     <source name="input 1"/> 
    </midline> 
    <midline type="A" name="mid3" hidden="false"> 
     <source name="input 1"/> 
    </midline> 
    <midline type="A" name="mid4" hidden="false"> 
     <source name="input 1"/> 
    </midline> 
</topline> 

с этим источником XML файл (реальные круговыми братьев и сестер):

<topline> 
    <midline type="A" name="mid1" hidden="true"> 
     <source name="off"/> 
    </midline> 
    <midline type="A" name="mid2" hidden="false"> 
     <source name="input 1"/> 
    </midline> 
    <midline type="A" name="mid3" hidden="false"> 
     <source name="input 1"/> 
    </midline> 
    <midline type="A" name="mid4" hidden="true"> 
     <source name="input 1"/> 
    </midline> 
</topline> 

снова желаемый, правильный результат получается.

Замечание: Использование оператора XPath mod для определения местоположения кругового брата и сестры.

+0

+1. Я должен был подумать об использовании 'mod()', это намного лучше, чем мой подход. – Tomalak