Есть ли способ добавить элементы в xml, если они еще не существуют?

Имея существующий xml, я хочу добавить новый узел, если он еще не существует в xml.

Я полный новичок в пути XML, и я начал с поиска в Google, потому что считаю, что это будет довольно стандартная проблема.

Я рассматриваю возможность использования для этого xmltask.

Я также нашел небольшой пример здесь

Я хочу создать макрос в Ant, который позволит моим потребителям регистрировать свои конечные точки.

Окончательная структура моего XML будет выглядеть так:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <endpoints>
    <endpoint url="serviceA" />
  </endpoints>
</configuration>

Мой макрос будет таким:

  <macrodef name="appendConfigEndpoints">
    <attribute name="filePath" />
    <attribute name="endpointUrl" />
    <sequential>
      <xmltask source="@{filePath}">
        <copy path="count(/configuration/endpoints/endpoint)" property="existsEndpoint" /> <!-- how to check if the endpoint exists -->
      </xmltask>
      <echo message="found ${existsEndpoint} in xml" />
      <if>
        <isfalse value="${existsEndpoint}"/>
        <then>
          <concat destfile="${currentScriptDirectory}/tempFile.xml">
            <string>&lt;endpoint url="@{endpointUrl}" /&gt;${line.separator}</string>
          </concat>
          <xmltask source="@{filePath}" dest="@{filePath}" outputter="simple:2">
            <insert path="/configuration/endpoints" file="${currentScriptDirectory}/tempFile.xml" position="under" />
          </xmltask>
          <delete file="${currentScriptDirectory}/tempFile.xml"/>
        </then>
        <else>
          <echo message="already exists @{endpointUrl} in xml" />
        </else>
      </if>
    </sequential>
  </macrodef>

Чтобы сгенерировать мой xml, я бы хотел вызвать цель следующим образом.

<appendConfigEndpoints filePath="file.xml" endpointUrl="serviceA" />
<appendConfigEndpoints filePath="file.xml" endpointUrl="serviceB" />
<appendConfigEndpoints filePath="file.xml" endpointUrl="serviceC" />
<appendConfigEndpoints filePath="file.xml" endpointUrl="serviceB" />

Но я еще не там, в настоящее время я даже не могу правильно сосчитать

07:29:32.844: found 0 in xml
07:29:32.876: found 0 in xml
07:29:32.882: found 0 in xml
07:29:32.889: found 0 in xml

но мой вывод в порядке, просто действительно не хватает работы счетчика

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

<configuration>
  <endpoints>
    <endpoint url="serviceA"></endpoint>
    <endpoint url="serviceB"></endpoint>
    <endpoint url="serviceC"></endpoint>
    <endpoint url="serviceB"></endpoint>
  </endpoints>
</configuration>

ОБНОВЛЕНИЕ: я, наконец, заставил это работать, и в основном проблема заключалась в том, что я не понимал последовательность и забыл о неизменности свойства... спасибо за помощь в ответе, это помогло мне добраться туда. в итоге выглядело так:

  <macrodef name="appendConfigEndpoints">
    <attribute name="filePath" />
    <attribute name="endpointUrl" />
    <sequential>
      <if>
        <not>
          <available file="@{filePath}"/>
        </not>
        <then>
          <echo message="@{filePath} not available, copy template and enrich." />
          <copy file="${currentScriptDirectory}/default/appl/sample.endpoints.xml" tofile="@{filePath}"/>
        </then>
      </if>
      <xmltask source="@{filePath}">
        <copy path="count(//endpoint[@url='@{endpointUrl}'])" property="endpointsCount" />
      </xmltask>
      <if>
        <equals arg1="${endpointsCount}" arg2="0" />
        <then>
          <xmltask source="@{filePath}" dest="@{filePath}" outputter="simple:2" clearBuffers="true">
            <insert path="/configuration/endpoints" xml="&lt;endpoint url='@{endpointUrl}' /&gt;${line.separator}" position="under" />
          </xmltask>
        </then>
        <else>
          <echo message="@{endpointUrl} already found in @{filePath}" />
        </else>
      </if>
      <var name="endpointsCount" unset="true" />
    </sequential>
  </macrodef>

person Miguel Costa    schedule 23.05.2019    source источник
comment
Вам нужно, чтобы набор конечных точек был уникальным, то есть, если serviceB уже присутствует, его не следует добавлять снова?   -  person martin clayton    schedule 23.05.2019
comment
Я так и предполагал, я, наконец, заставил это работать (с помощью коллеги), но с очень уродливой работой. Также очень уродливо, но я не мог повторно вызывать эту цель, я полагаю, потому что файл назначения закрывается только тогда, когда основная цель откуда Я называю, что мой макрос работает. Например, если бы я вызывал serviceA, serviceB, serviceB подряд, файл всегда был бы пустым при выполнении проверки. Мне нужно было переместить это в задачу-оболочку   -  person Miguel Costa    schedule 24.05.2019


Ответы (1)


Свойство existsEndpoint имеет только одно значение из-за неизменности свойств Ant. Однако вы можете сделать свойство локализованным в макросе, добавив

<local name="existsEndpoint"/>

в начале блока <sequential>. Тогда каждый вызов макроса может иметь собственное значение свойства.

person martin clayton    schedule 23.05.2019
comment
Мне потребовалось некоторое время, чтобы понять, что вы сказали, но вы правы. Я не использовал локальный, потому что xpath не позволяет мне, или я не знаю, как это сделать, но снятие сброса позволило мне решить проблему. - person Miguel Costa; 24.05.2019