2010-08-04 2 views
0

Мой файл XML выглядит следующим образом:Как изменить значение параметра в XML с помощью Perl?

<Configuration> 
    <Parameters> 
     <Component Name="Aas"> 
      <Group Name="PrivilegesMapping"> 
       <Parameter Name="PrivilegesLoaderInterval"> 
        <Description> 
        The interval (in minute) 
        </Description> 
        <Type>Integer</Type> 
        <Restriction> 
         <RequiresRestart>true</RequiresRestart> 
         <MinVal/> 
         <MaxVal/> 
         <MaxLength/> 
         <Mandatory>true</Mandatory> 
         <Lov/> 
         <Level>5</Level> 
        </Restriction> 
        <Value> 
         <Item Value="5"/> 
        </Value> 
       </Parameter> 
      </Group> 
      <Group Name="DomainsMapping"> 
       <Parameter Name="DomainLoaderInterval"> 
        <Description> 
        The interval (in minute) 
        </Description> 
        <Type>Integer</Type> 
        <Restriction> 
         <RequiresRestart>true</RequiresRestart> 
         <MinVal/> 
         <MaxVal/> 
         <MaxLength/> 
         <Mandatory>true</Mandatory> 
         <Lov/> 
         <Level>5</Level> 
        </Restriction> 
        <Value> 
         <Item Value="5"/> 
        </Value> 
       </Parameter> 
       <Parameter Name="MapSource"> 
        <Description> 
        Set the source of the domains list 
        </Description> 
        <Type>Enum</Type> 
        <Restriction> 
         <RequiresRestart>true</RequiresRestart> 
         <MinVal/> 
         <MaxVal/> 
         <MaxLength/> 
         <Mandatory>true</Mandatory> 
         <Lov> 
          <Val>FILE</Val> 
          <Val>DATABASE</Val> 
          <Val>NONE</Val> 
         </Lov> 
         <Level>5</Level> 
        </Restriction> 
        <Value> 
         <Item Value="FILE"/> 
        </Value> 
       </Parameter> 
      </Group> 
      <Group Name="SystemsMapping"> 
       <Parameter Name="MapSource"> 
        <Description> 
        </Description> 
        <Type>Enum</Type> 
        <Restriction> 
         <RequiresRestart>true</RequiresRestart> 
         <MinVal/> 
         <MaxVal/> 
         <MaxLength/> 
         <Mandatory>true</Mandatory> 
         <Lov> 
          <Val>API</Val> 
          <Val>FILE</Val> 
          <val>NONE</Val> 
         </Lov> 
         <Level>5</Level> 
        </Restriction> 
        <Value> 
         <Item Value="NONE"/> 
        </Value> 
       </Parameter> 
       <Parameter Name="SystemsLoaderInterval"> 
        <Description> 
        The interval (in minute) 
        </Description> 
        <Type>Integer</Type> 
        <Restriction> 
         <RequiresRestart>true</RequiresRestart> 
         <MinVal/> 
         <MaxVal/> 
         <MaxLength/> 
         <Mandatory>true</Mandatory> 
         <Lov/> 
         <Level>5</Level> 
        </Restriction> 
        <Value> 
         <Item Value="5"/> 
        </Value> 
       </Parameter> 
      </Group> 
     </Component> 
    </Parameters> 
</Configuration> 

Я хотел бы изменить значение от <Item Value="NONE"/> до <Item Value="API"/> под <Parameter Name="MapSource">.

+1

У вас есть процессор XSLT? Это тривиально в XSL. –

ответ

0

Вспомнив, что обработка XML с регулярными выражениями usually a really bad idea с Perl вы могли

#! /usr/bin/perl 

use warnings; 
use strict; 

system("xsltproc", "fix.xsl", "input.xml") == 0 
    or warn "$0: xsltproc failed\n"; 

и fix.xsl из

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="/Configuration/Parameters/Component/Group/Parameter[@Name='MapSource']/Value/Item[@Value='NONE']"> 
    <xsl:element name="Item"> 
     <xsl:attribute name="Value">API</xsl:attribute> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

, чтобы получить желаемый результат:

$ diff -ub input.xml <(./prog.pl) 
--- input.xml 
+++ /dev/fd/63 
@@ -1,3 +1,4 @@ 
+<?xml version="1.0"?> 
<Configuration> 
    <Parameters> 
     <Component Name="Aas"> 
@@ -82,7 +83,7 @@ 
         <Level>5</Level> 
        </Restriction> 
        <Value> 
-      <Item Value="NONE"/> 
+      <Item Value="API"/> 
        </Value> 
       </Parameter> 
       <Parameter Name="SystemsLoaderInterval">

В если вы не знакомы, <(./prog.pl) использует bash process substitution, поэтому команда diff сравнивает input.xml с выходом краткой программы Perl.

Чтобы заменить все элементы Item, которые являются потомками параметров MapSource, используйте таблицу стилей ниже. Обратите внимание, как это более гибко в отношении структуры исходного документа.

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="//Parameter[@Name='MapSource']//Item"> 
    <xsl:element name="Item"> 
     <xsl:attribute name="Value">API</xsl:attribute> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

Теперь переход от входа к выходу является

$ diff -ub input.xml <(./prog.pl) 
--- input.xml 
+++ /dev/fd/63 
@@ -1,3 +1,4 @@ 
+<?xml version="1.0"?> 
<Configuration> 
    <Parameters> 
     <Component Name="Aas"> 
@@ -59,7 +60,7 @@ 
         <Level>5</Level> 
        </Restriction> 
        <Value> 
-      <Item Value="FILE"/> 
+      <Item Value="API"/> 
        </Value> 
       </Parameter> 
      </Group> 
@@ -82,7 +83,7 @@ 
         <Level>5</Level> 
        </Restriction> 
        <Value> 
-      <Item Value="NONE"/> 
+      <Item Value="API"/> 
        </Value> 
       </Parameter> 
       <Parameter Name="SystemsLoaderInterval">
+0

Мне понравилось это решение. Спасибо. В: Как я могу изменить fix.xsl, чтобы избежать использования 'NONE' в пути [@ Value = 'NONE']. Я не хочу заботиться о том, какая строка в настоящее время занята Toren

+0

@Toren Спасибо! См. Обновленный ответ. –

0

Самый быстрый (простой) способ я нашел XML::XPath (даже меньше, с File::Slurp - см редактировать историю для предварительного чавкать кода):

use strict; 
use warnings; 
use File::Slurp(); 
use XML::XPath; 
use XML::XPath::XMLParser; 

my $path = '/path/to/file/config.xml'; 
my $xp = XML::XPath->new(filename => $path); 
$xp->setNodeText(q{//Parameter[@Name='MapSource']/Value/Item/@Value} 
       , 'API' 
       ); 
File::Slurp::write_file($path, $xp->findnodes_as_string('/')); 
+0

Спасибо. Хорошее решение – Toren

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