
У меня сложная проблема. Мне нужно внести небольшое изменение в большое количество xml-файлов (более 500). Изменение заключается в переключении значения с «false» на «true». Строка, которую нужно изменить, выглядит так:
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
И он должен стать:
<SizeIsMeasuredLineLine>true</SizeIsMeasuredLineLine>
К сожалению, в каждом файле есть множество экземпляров этого набора тегов, поэтому мы не можем выполнить простой поиск и замену. Уникальность этого набора тегов заключается в том, что они идут через несколько строк после:
<CID>ITEMNAME.BUS.ITEMNAME.DKV</CID>
Однако у каждого файла свое имя элемента, поэтому я использовал подстановочные знаки, чтобы отфильтровать их.
<CID>.*BUS..*.DKV</CID>
Проблема в том, что количество строк между частью CID и строкой, которую нужно изменить, не совпадает от файла к файлу. Мне нужно найти способ использовать подстановочные знаки для строк между ними и заменить строку Size.
Есть идеи? Я уже пробовал:
<CID>.*BUS..*.DKV</CID>.*?<SizeIsMeasuredLineLine>true</SizeIsMeasuredLineLine>
Но по какой-то причине это не сработало. Спасибо заранее!
Редактировать в ответ на комментарий:
По сути, я хочу сказать, что код выглядит следующим образом:
<CID>ITEMNAME.BUS.ITEMNAME.DKV</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
А другие разделы кода выглядят так:
<CID>ITEMNAME.COLR.ITEMNAME.FCLR</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
в других местах кода. Поэтому я использую строку CID .BUS .DKV в качестве отправной точки. По сути, мне нужно изменить первое вхождение строки SizeisMeasured, которая идет сразу ПОСЛЕ строки CID .BUS .DKV. Но между ними есть много других строк (ни одна из которых не соответствует от файла к файлу), которые мне не нужны и которые портят мой поиск.
решение1
Вы можете использовать отрицательный просмотр вперед, как здесь. Поиск
(?!<CID>.*BUS..*.DKV</CID>(.*?))<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
и заменить на
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
Регулярное выражение, соответствие . новая строка
Отрицательный просмотр вперед (?!a)
и отрицательный просмотр назад (?<!a)
, также называются Lookaround. Lookaround сопоставляет символы, но затем отказывается от сопоставления, возвращая только результат: совпадение или несовпадение.
Больше информации можно найти здесь Утверждения нулевой длины Lookahead и Lookbehind
решение2
Разбор XML с соблюдением иерархии с помощью регулярных выражений излишне сложен. Я бы использовал совершенно другой инструмент, который явно разработан для того, что вы пытаетесь сделать, а именно, преобразование XML. Я говорю о XSLT. Итак, вот мое решение вашей проблемы с использованием XSLT. Существует ряд веб-сайтов, которые вы можете использовать для преобразования XML с помощью XSLT, или вы можете запустить XSLT локально.
Проблема была бы проще, если бы каждая из ваших групп (CID, за которым следует SizeIsMeasuredLineLine) находилась в пределах одного родителя, но код ниже смотрит на первый предшествующий CID-родственный элемент, чтобы узнать, какое у него значение. Если его значение соответствует регулярному выражению (ITEMNAME.[^.]+.ITEMNAME..+), то он меняет false на true. Все остальные элементы просто копируются в вывод.
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="SizeIsMeasuredLineLine[matches(preceding-sibling::CID[1], 'ITEMNAME\.[^.]+\.ITEMNAME\..+')]">
<xsl:copy>TRUE</xsl:copy>
</xsl:template>
Вот пример XML, который я создал для проверки вышесказанного:
<?xml version="1.0" encoding="UTF-8"?>
<parent>
<CID>ITEMNAME.BUS.ITEMNAME.DKV</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
<CID>ITEMNAME.COLR.ITEMNAME.FCLR</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
<CID>ITEMNAME.BUS.122.DKV</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
<CID>ITEMNAME.COLR.ITEMNAME.FCLR</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
<CID>ITEMNAME.BUS.44.DKV</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
<CID>ITEMNAME.COLR.ITEMNAME.FCLR</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
<CID>ITEMNAME.BUS.33.DKV</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
<CID>ITEMNAME.COLR.ITEMNAME.FCLR</CID>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<tag>Some Number of Other lines</tag>
<SizeIsMeasuredLineLine>false</SizeIsMeasuredLineLine>
</parent>