我正在尝试使用Perl中的XML::LibXML
在节点值的开头将XML元素添加到XML中的节点。我的XML是:
<root>
<book>
<title>
Test title for xml
</title>
<para n=1> para1 information </para>
<para n=2><head value="PARA HEADING"/>para2 information<subpara i=1>subpara Info</subpara><xyz/></para>
</book>
</root>
我想要的输出是:
<root>
<book>
<title>
Test title for xml
</title>
<para n=1><head value="PARA HEADING"/>para1 information </para>
<para n=2><head value="PARA HEADING"/>para2 information<subpara i=1><head value="PARA HEADING"/>Subpara Info</subpara><xyz/></para>
</book>
</root>
我想添加一个子节点&#39; head&#39;如上所述,如果它没有出现在&#39; para&#39;或者&#39; subpara&#39;。
我试过这段代码:
#!/usr/local/bin/perl5.8.8
use XML::LibXML;
my $xml_parser = XML::LibXML->new();
my $xml_doc = $xml_parser->parse_file( xml_file . xml );
my $root = $xml_doc->getDocumentElement();
my $xml_xc = XML::LibXML::XPathContext->new( $root );
my @array_list = ( para, deck );
foreach my $xml_sections ( $xml_xc->findnodes( '//*' ) ) {
if ( $xml_sections->nodeName ne "head" ) {
my $marker_flag = 0;
foreach my $first_child ( $xml_sections->childNodes() ) {
if ( $first_child->nodeName eq "head" ) {
$marker_flag = 1;
last;
}
}
if ( !$marker_flag ) {
foreach my $array_elt ( @array_list ) {
if ( $array_elt eq $xml_sections->nodeName ) {
my $new_tag = $xml_doc->createElement( "head" );
my $value = "PARA HEADING";
my $att1 = $xml_doc->createAttribute( "value", "$value" );
$new_tag->setAttributeNode( $att1 );
$xml_sections->addChild( $new_tag );
}
}
}
}
}
print $root->toString();
exit 0;
我的输出是:
<root>
<book>
<title>
Test title for xml
</title>
<para n=1>para1 information <head value="PARA HEADING"/></para>
<para n=2><head value="PARA HEADING"/>para2 information<subpara i=1>subpara Info<head value="PARA HEADING"/></subpara><xyz/></para>
</book>
</root>
我怎样才能做到这一点?
答案 0 :(得分:1)
您正在寻找XML::LibXML::Node
insertBefore
和addChild
方法
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use XML::LibXML;
my $dom = XML::LibXML->load_xml( IO => \*DATA );
for my $node ( $dom->findnodes("//para | //subpara") ) {
my $newnode = XML::LibXML->load_xml( string => '<head value="PARA HEADING"/>' )->findnodes('//*')->[0];
my @children = $node->childNodes();
if ( !@children ) {
$node->addChild($newnode);
} elsif ( $children[0]->nodeName ne 'head' ) {
$node->insertBefore( $newnode, $children[0] );
}
}
print $dom->toString;
__DATA__
<root>
<book>
<title>
Test title for xml
</title>
<para n="1"> para1 information </para>
<para n="2"><head value="PARA HEADING"/>para2 information<subpara i="1">subpara Info</subpara><xyz/></para>
</book>
</root>
输出:
<?xml version="1.0"?>
<root>
<book>
<title>
Test title for xml
</title>
<para n="1"><head value="PARA HEADING"/> para1 information </para>
<para n="2"><head value="PARA HEADING"/>para2 information<subpara i="1"><head value="PARA HEADING"/>subpara Info</subpara><xyz/></para>
</book>
</root>
答案 1 :(得分:1)
你为自己制造的东西非常困难!例如,除非您的XML数据具有非默认名称空间,否则不需要涉及XML::LibXML::XPathContext
,而您的样本不会。而且,
像para
这样的subpara
和n=1
元素的属性值应该有引号,给出n="1"
等等
这是一个使用XPath表达式查找所有para
或subpara
元素的解决方案,并使用exists
检查每个元素是否已经有head
子元素。标量$head
设置了您要插入的数据,并在找到的每个元素的第一个子元素之前插入它的克隆
use strict;
use warnings;
use XML::LibXML;
my $parser = XML::LibXML->new;
my $doc = $parser->parse_fh(*DATA);
my $head = $parser->parse_balanced_chunk('<head value="PARA HEADING"/>');
for my $para ( $doc->findnodes('//para | //subpara') ) {
if ( not $para->exists('head') ) {
$para->insertBefore($head->cloneNode(1), $para->firstChild);
}
}
print $doc;
__DATA__
<root>
<book>
<title>
Test title for xml
</title>
<para n="1"> para1 information </para>
<para n="2"><head value="PARA HEADING"/>para2 information<subpara i="1">subpara Info</subpara><xyz/></para>
</book>
</root>
<?xml version="1.0"?>
<root>
<book>
<title>
Test title for xml
</title>
<para n="1"><head value="PARA HEADING"/> para1 information </para>
<para n="2"><head value="PARA HEADING"/>para2 information<subpara i="1"><head value="PARA HEADING"/>subpara Info</subpara><xyz/></para>
</book>
</root>
答案 2 :(得分:-1)
此外,您可以使用其<xsl:when>
和<xsl:otherwise>
逻辑运行XSLT转换。作为信息,XSLT是声明性的,专用编程语言(与SQL相同,但与数据库相同)专门用于转换,样式化,重新格式化或重构XML文档。
Perl ( generic script )
use XML::LibXML;
use XML::LibXSLT;
my $xml_parser = XML::LibXML->new();
my $xml_doc = $xml_parser->parse_file($XML_FILENAME);
my $xslt_parser = XML::LibXSLT->new;
my $xsl_doc = $xml_parser->parse_file($XSL_FILENAME);
my $stylesheet = $xslt_parser->parse_stylesheet($xsl_doc);
my $results = $stylesheet->transform($xml_doc);
my $output = $stylesheet->output_string($results);
print $stylesheet->output_string($results);
XSLT (另存为上面使用的.xsl文件)
<?xml version="1.0" ?>
<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="para" name="paratemplate">
<xsl:choose>
<xsl:when test="string-length(head/@value)>0">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<para>
<xsl:apply-templates select="@*"/>
<xsl:element name="head">
<xsl:attribute name="value">PARA HEADING</xsl:attribute>
</xsl:element>
<xsl:apply-templates select="text()"/>
</para>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="subpara" name="subparatemplate">
<xsl:choose>
<xsl:when test="string-length(head/@value)>0">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<subpara>
<xsl:apply-templates select="@*"/>
<xsl:element name="head">
<xsl:attribute name="value">PARA HEADING</xsl:attribute>
</xsl:element>
<xsl:apply-templates select="text()"/>
</subpara>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
<?xml version="1.0"?>
<root>
<book>
<title>
Test title for xml
</title>
<para n="1"><head value="PARA HEADING"/> para1 information </para>
<para n="2"><head value="PARA HEADING"/>para2 information<subpara i="1"><head value="PARA HEADING"/>subpara Info</subpara><xyz/></para>
</book>
</root>