2015-01-09 2 views
0

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

Что я хочу сделать, это обновить один и тот же узел более одного раза. Еще один способ взглянуть на это - я хотел бы сделать несколько проходов в документе, и каждый проход может обновить один и тот же узел.

Все мои погуглить намеки на использование «режим» атрибута XSL: шаблон, но все примеры «режим» атрибут включает вывод узла, дважды - как и в случае использования заголовка в оглавление и снова использовать его как заголовок главы. Я не хочу выводить узел дважды, я хочу его дважды обновить.

Мой образец XSLT:

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

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

    <!-- wrap all BBB nodes in parenthesis --> 
    <xsl:template match="BBB" > 
    <xsl:copy> 
     (<xsl:apply-templates select="@*|node()" />) 
    </xsl:copy> 
    </xsl:template> 

    <!-- any BBB that has a CCC should get an attribute indicating so --> 
    <xsl:template match="BBB[CCC]"> 
    <xsl:copy> 
     <xsl:attribute name="hasC">true</xsl:attribute> 
     <xsl:apply-templates select="@*|node()" /> 
    </xsl:copy> 
    </xsl:template> 


</xsl:stylesheet> 

Мой образец XML-документ:

<?xml version="1.0" encoding="UTF-8"?> 
<source> 

<AAA> 
    <BBB>Bee bee bee</BBB> 
    <BBB>Bee two bee two bee two</BBB> 
</AAA> 
<AAA> 
    <BBB/> 
    <CCC> 
      <DDD/> 
    </CCC> 
    <BBB> 
      <CCC/> 
    </BBB> 
</AAA> 

</source> 

Выходной ток:

<?xml version="1.0" encoding="UTF-8"?><source> 

<AAA> 
    <BBB> 
     (Bee bee bee) 
    </BBB> 
    <BBB> 
     (Bee two bee two bee two) 
    </BBB> 
</AAA> 
<AAA> 
    <BBB> 
     () 
    </BBB> 
    <CCC> 
      <DDD/> 
    </CCC> 
    <BBB hasC="true"> 
      <CCC/> 
    </BBB> 
</AAA> 

</source> 

Как вы можете видеть, узел BBB, который имеет " CCC 'обновляется только один раз, со вторым шаблоном - первый шаблон не изменял его. В идеале я хочу, чтобы выход был

<BBB hasC="true"> 
    (<CCC/>) 
</BBB> 

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

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

EDIT: Основываясь на большом количестве комментариев, которые я получаю, я думаю, что я неправильно понимаю что-то фундаментальное в XSLT и преобразованиях.

Проблема у меня есть: у меня есть куча XML-документов, соответствующих спецификации. Эта спецификация была обновлена ​​другой группой людей, поэтому мне нужно создать пакетный/сценарийный процесс, чтобы иметь возможность обновлять большое количество этих XML-документов, чтобы они соответствовали этой новой спецификации.

Некоторые из этих новых обновлений - это такие вещи, как следующее.

1) <string lang="FR">hello</string> необходимо изменить, чтобы <string lang="fra">hello</string>

2) <a><b><string>Color</string><b></a> необходимо изменить, чтобы <a><b><string>Colour</string></b></a>, но не трогайте <a><c><string>Color</string></c></a>

3) все <orgName><string>***anytext***</string></orgName> необходимость изменения в <orgName><string>My Company: ***anytext***</string></orgName>

4) все <orgName><string></string></orgName> узлов необходимо изменить на <organisationName><string></string></orgisationName>

И так далее. Существует множество конкретных обновлений, которые могут применяться к одним и тем же узлам несколько раз, и их достаточно, чтобы сделать несколько проходов в файлах, кажется лучшей идеей, а затем созданием одного шаблона catch-all, который объединяет все эти обновления в один большой шаблон.

Должен ли я использовать XSLT, чтобы попытаться это сделать? Это случай, когда мне нужно разбить эти изменения на несколько файлов и связать их по сценарию? Могу ли я сделать все эти обновления в одном файле .xslt?

+1

Если вы хотите, чтобы весь контент в узлах 'BBB' был завернут в круглые скобки, почему бы не просто обернуть' 'в' 'как в обработке шаблонов' BBB'? Тогда результатом будет () '. –

+0

Причина, по которой я не хочу их комбинировать, - это довольно много таких шаблонов, которые могут изменить один и тот же узел.Попытка объединить их все может усложниться. Другая причина заключается в том, что эти шаблоны соответствуют определенным правилам, поступающим из другой группы. В этом случае вы можете создать изображение «Чтобы соответствовать стандарту 1.2.3c, вам нужно обернуть элементы BBB в скобках» и «Чтобы соответствовать стандарту 1.5.2a, вам нужно добавить атрибут hasC к узлам BBB». Сохранение отдельных шаблонов облегчит чтение/обслуживание этого файла. –

+0

IMHO, цепочка двух преобразований будет * более сложной. –

ответ

3

Так же, как, например, для вашего обновленного примера ввода: После XSLT

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
<xsl:output method="xml" doctype-public="XSLT-compat" 
     encoding="UTF-8" indent="yes" /> 
<xsl:strip-space elements="*" /> 
    <!-- identity transform (copy over the document) --> 
    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()" /> 
    </xsl:copy> 
    </xsl:template> 
    <!-- wrap all BBB nodes in parenthesis --> 
    <xsl:template match="BBB"> 
    <xsl:copy> 
     <xsl:if test="CCC"> 
      <xsl:attribute name="hasC">true</xsl:attribute> 
     </xsl:if> 
     (<xsl:apply-templates select="@*|node()" />) 
    </xsl:copy> 
    </xsl:template> 
    <xsl:template match="orgName[string]"> 
    <organisationName> 
     <xsl:apply-templates /> 
    </organisationName> 
    </xsl:template> 
    <xsl:template match="a/b/string[text()='Color']"> 
    <xsl:text>Colour</xsl:text> 
    </xsl:template> 
    <xsl:template match="orgName/string/text()"> 
    <xsl:text>Company:</xsl:text> 
    <xsl:value-of select="." /> 
    </xsl:template> 
    <xsl:template match="string[@lang='FR']"> 
    <xsl:copy> 
     <xsl:attribute name="lang">fra</xsl:attribute> 
     <xsl:apply-templates /> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

при нанесении на пример входного XML

<?xml version="1.0" encoding="UTF-8"?> 
<source> 
<AAA> 
    <BBB>Bee bee bee</BBB> 
    <BBB>Bee two bee two bee two</BBB> 
    <test> 
     <string lang="FR">hello</string> 
    </test> 
    <a> 
     <b> 
     <string>Color</string> 
     </b> 
    </a> 
    <a> 
     <c> 
     <string>Color</string> 
     </c> 
    </a> 
    <orgName> 
     <string>***anytext***</string> 
    </orgName> 
    <orgName> 
     <notstring>***anytext***</notstring> 
    </orgName> 
    </AAA> 
    <AAA> 
     <BBB /> 
     <CCC> 
     <DDD /> 
     </CCC> 
    <BBB> 
     <CCC /> 
    </BBB> 
    </AAA> 
</source> 

производит следующий вывод:

<?xml version="1.0" encoding="UTF-8"?> 
<source> 
    <AAA> 
    <BBB>(Bee bee bee)</BBB> 
    <BBB>(Bee two bee two bee two)</BBB> 
    <test> 
     <string lang="fra">hello</string> 
    </test> 
    <a> 
     <b>Colour</b> 
    </a> 
    <a> 
     <c> 
     <string>Color</string> 
     </c> 
    </a> 
    <organisationName> 
     <string>Company:***anytext***</string> 
    </organisationName> 
    <orgName> 
    <notstring>***anytext***</notstring> 
    </orgName> 
    </AAA> 
    <AAA> 
    <BBB>()</BBB> 
    <CCC> 
     <DDD /> 
    </CCC> 
    <BBB hasC="true"> 
    (<CCC />) 
    </BBB> 
    </AAA> 
</source> 

Вы уже что 4 добавленных требования в вашем обновлении являются лишь примером для списка много изменений, которые должны быть применены к входному XML, так что это всего лишь пример того, как различные изменения на один и те же узлы, может быть обработаны - например .:

<xsl:template match="orgName[string]"> 

соответствует узлу orgName, который содержит узел string. По

<organisationName> 
    <xsl:apply-templates /> 
</organisationName> 

этот шаблон переименовывает orgName к organisationName.

Второй шаблон соответствует text() в виде string узла в orgName узле:

<xsl:template match="orgName/string/text()"> 

и добавляет Company: перед этим текстом:

<xsl:text>Company:</xsl:text> 
    <xsl:value-of select="." /> 

Результат обоих шаблонов:

<organisationName> 
    <string>Company:***anytext***</string> 
</organisationName> 

orgName of thi s из примера ввода

<orgName><notstring>***anytext***</notstring></orgName> 

, а также текст остается неизменным, orgName не содержит string.

Я также удалил ваш шаблон, соответствующий BBB[CCC], чтобы установить атрибут hasC. Вместо этого, я добавил

<xsl:if test="CCC"> 
    <xsl:attribute name="hasC">true</xsl:attribute> 
</xsl:if> 

в соответствии шаблона BBB.

Я не буду рекомендовать использовать XSLT для применения всех необходимых изменений, так как я не знаю всех конкретных изменений, которые необходимо применить - это действительно зависит от ввода и полной спецификации необходимых изменений. Я просто хотел привести пример того, как изменения, упомянутые в вашем вопросе, могут быть обработаны одним XSLT.

+0

Я бы подумал, что четыре дополнительных правила, которые я добавил, столкнулись бы с той же проблемой, что и мой пример BBB/CCC, но вы обрабатывали каждое правило своим собственным шаблоном. Это заставляет меня думать, что я, вероятно, могу справиться с большинством преобразований с помощью одного шаблона, и в редких случаях, когда я не могу (BBB/CCC), я могу просто прокомментировать это. Спасибо за примеры, они определенно помогут мне! –

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