XSLT: когда элемент существует, добавьте его и измените значение, в противном случае добавьте элемент со значением - PullRequest
2 голосов
/ 08 октября 2010

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

Вот пример для лучшего понимания:

<root>
    <group>
        <element1>SomeValue1</element1>
        <element2>SomeValue2</element2>
    </group>
</root>

Допустим, я всегда хочу element1, element2 и element3 со значениями Changed1, Changed2, Changed3.

Это должно закончиться так:

<root>
    <group>
        <element1>Changed1</element1>
        <element2>Changed2</element2>
        <element3>Changed3</element3>
    </group>
</root>

Что я могу сделать, чтобы это произошло?Благодарим вас заранее

Денис

Ответы [ 4 ]

3 голосов
/ 08 октября 2010

Я не уверен, что это самое элегантное решение в мире, но я думаю, что это, вероятно, сделает то, что вы ищете:

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

<!--  If the element exists, do what you want to do -->
<xsl:template match="element1">
    <xsl:copy>Changed1</xsl:copy>
</xsl:template>

<xsl:template match="element2">
    <xsl:copy>Changed2</xsl:copy>
</xsl:template>

<xsl:template match="element3">
    <xsl:copy>Changed3</xsl:copy>
</xsl:template>

<!--  If the element doesn't exist, add it -->
<xsl:template match="group">
    <xsl:copy>
        <xsl:apply-templates/>
        <xsl:if test="not(element1)">
            <element1>Changed1</element1>
        </xsl:if>
        <xsl:if test="not(element2)">
            <element2>Changed2</element2>
        </xsl:if>
        <xsl:if test="not(element3)">
            <element3>Changed3</element3>
        </xsl:if>
    </xsl:copy>
</xsl:template>

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

</xsl:stylesheet>

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

Конечно, если значения постоянны (то есть element1, element2 и element3 всегда будут иметь одинаковые значения независимо от того, являются ли они новыми или обновленными), тогда у вас может быть что-то более простое:

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

<!--  If the element exists, remove it -->
<xsl:template match="element1 | element2 | element3"/>

<!--  Now put in your preferred elements -->
<xsl:template match="group">
    <xsl:copy>
        <xsl:apply-templates/>
            <element1>Changed1</element1>
            <element2>Changed2</element2>
            <element3>Changed3</element3>
    </xsl:copy>
</xsl:template>

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

</xsl:stylesheet>

Что по существу удаляет исходные "элементные" узлы и помещает ваши на их место.

1 голос
/ 08 октября 2010

Вот более общее решение . Имена элементов можно указывать отдельно от кода:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:my="my:my" exclude-result-prefixes="my">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <my:newValues>
      <element1>Changed1</element1>
      <element2>Changed2</element2>
      <element3>Changed3</element3>
    </my:newValues>

    <xsl:variable name="vElements" select="document('')/*/my:newValues/*"/>

 <xsl:template match="*" name="identity" mode="copy">
     <xsl:element name="{name()}">
       <xsl:copy-of select="namespace::*[not(name()='my' or name()='xsl')]"/>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:element>
 </xsl:template>

 <xsl:template match="*">
  <xsl:if test="not($vElements[name()=name(current())])">
   <xsl:call-template name="identity"/>
  </xsl:if>
 </xsl:template>

 <xsl:template match="group">
  <xsl:copy>
   <xsl:apply-templates select="node()"/>
    <xsl:apply-templates select="$vElements" mode="copy"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному документу XML :

<root>
    <group>
        <element1>SomeValue1</element1>
        <element2>SomeValue2</element2>
    </group>
</root>

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

<root>
    <group>
        <element1>Changed1</element1>
        <element2>Changed2</element2>
        <element3>Changed3</element3>
    </group>
</root>

Примечание : казалось бы, сложная обработка, которая отбрасывает пространства имен "xsl" anf "my", не требуется, если изменяемые элементы находятся в отдельном документе. Этот код намеренно помещает изменяемые элементы в тот же документ, что и таблица стилей xslt, для демонстрационных целей. На практике будет использоваться <xsl:copy-of select="$vModifiedDoc/*">.

0 голосов
/ 08 октября 2010

Просто для удовольствия, решение XSLT 2.0:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="vAdd" as="element()*">
        <element1>Changed1</element1>
        <element2>Changed2</element2>
        <element3>Changed3</element3>
    </xsl:variable>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="group/*[name()=$vAdd/name()]"/>
    <xsl:template match="group/*[last()]" priority="1">
        <xsl:next-match/>
        <xsl:apply-templates select="$vAdd"/>
    </xsl:template>
</xsl:stylesheet>

Выход:

<root>
    <group>
        <element1>Changed1</element1>
        <element2>Changed2</element2>
        <element3>Changed3</element3>
    </group>
</root>
0 голосов
/ 08 октября 2010

Ваш пример может быть упрощен. Похоже, вы можете просто сгенерировать 3 «измененные» значения для каждого элемента, с которым вы сталкиваетесь ... так что я предполагаю, что это немного сложнее, чем в реальной жизни.

В любом случае, если измененное значение не является заменой, а фактически является модификацией исходного значения, вы, вероятно, можете использовать for-each для group с, а затем сгенерировать 3 элемента, где значение каждого элемента основано на элементе xsl-if, который проверяет, существует ли исходное значение, и использует его, если так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...