Использовать xmlstarlet для добавления недостающих элементов? - PullRequest
0 голосов
/ 20 марта 2020

У меня есть несколько записей о поставщиках, которые содержат несколько адресов, например,

<vendor>
  <addresses>
    <address primary="yes">
      <line1 />
      <city />
      <state />
      ....
     </address>
     <address primary="no">
      <line1 />
      <city />
      <state />
      ....
     </address>
  </addresses>
</vendor>

Отсутствуют некоторые обязательные элементы, препятствующие обновлению записей. Можно ли использовать xmlstarlet для добавления элемента со значением по умолчанию, если он отсутствует?

Ответы [ 2 ]

2 голосов
/ 21 марта 2020

Вот простой пример. Я буду использовать xmllint --auto для источника xml. Затем мы добавим элемент <add-me> в качестве дочернего элемента <info>, если он не существует с использованием шаблона преобразования идентификаторов.

Источник xml:

xmllint --auto
<?xml version="1.0"?>
<info>abc</info>

Добавить отсутствующий элемент:

xmllint --auto | xsltproc add-missing.xsl -
<?xml version="1.0"?>
<info><add-me>some stuff</add-me>abc</info>

add-missing.xsl:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="info">
        <xsl:copy>
            <xsl:if test="not(add-me)">
                <add-me>some stuff</add-me>
            </xsl:if>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
0 голосов
/ 23 марта 2020

Другой вариант XSLT с xmlstarlet - использовать переменную, которая содержит обязательные элементы (со значениями по умолчанию или без них) и обрабатывать их как набор узлов (используя поддерживаемую функцию exsl:node-set()).

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

Пример ...

XML Вход (вход. xml)

<vendor>
    <addresses>
        <address primary="yes">
            <line1>address 1 line1</line1>
            <state>address 1 state1</state>
        </address>
        <address primary="no">
            <line1>address 2 line1</line1>
            <city>address 2 city</city>
            <state>address 2 state</state>
        </address>
    </addresses>
</vendor>

XSLT 1.0 (so.xsl)

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

  <xsl:variable name="req_elems">
    <req>
      <line1/>
      <city/>
      <state/>
      <country/>      
    </req>
  </xsl:variable>

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

  <xsl:template match="address">
    <xsl:variable name="ctx" select="."/>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each select="exsl:node-set($req_elems)/req/*">
        <xsl:choose>
          <xsl:when test="$ctx/*[local-name()=local-name(current())]">
            <xsl:apply-templates select="$ctx/*[local-name()=local-name(current())]"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="."/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

XML Выход

<vendor>
  <addresses>
    <address primary="yes">
      <line1>address 1 line1</line1>
      <city/>
      <state>address 1 state1</state>
      <country/>
    </address>
    <address primary="no">
      <line1>address 2 line1</line1>
      <city>address 2 city</city>
      <state>address 2 state</state>
      <country/>
    </address>
  </addresses>
</vendor>

Примечание. Это работает, только если в * разрешены только элементы 1023 * совпадают с $req_elements. Например, если в адресе есть элемент с именем «foo», он будет удален из вывода.

...