如何清除 xml 字符串中的元素
How to clean elements in xml string
我有一个 xml,其中标签可以在元素中包含一个、两个或多个 space 和句点 (.)。
the xml:
$xml='<?xml version="1.0" encoding="UTF-8"?>
<xmldata>
<SalesHeader>
<DocType>Order</DocType>
<No>1002</No>
<SellToCustomerNo>CustNo</SellToCustomerNo>
<SellToCustomerName>Customer Name</SellToCustomerName>
<SellToCustomerName2 />
<SellToEmail>testemail@aol.com</SellToEmail>
<OrderDate>04/03/13</OrderDate>
<ExtDocNo />
<ShipToName>Customer Ship to</ShipToName>
<ShipToCountry />
<TaxLiable>No</TaxLiable>
<TaxAreaCode />
<RequestedDeliveryDate />
<Shipping Agent>UPS</Shipping Agent>
<Shipping Agent Service>Ground New</Shipping Agent Service>
<Tracking Numbers>123123212,1231231321</Tracking Numbers>
<SalesLine>
<ItemNo.>12-34343-23</ItemNo.>
<Description>Item Description</Description>
<Quantity>1</Quantity>
<UnitPrice>79.00</UnitPrice>
</SalesLine>
<SalesLine>
<ItemNo.>12-34343-23</ItemNo.>
<Description>Item Description</Description>
<Quantity>1</Quantity>
<UnitPrice>79.00</UnitPrice>
</SalesLine>
</SalesHeader>
</xmldata>';
我的代码:
preg_replace(array('/(<\/?)[. ]+(\w*)(\/?>)/','/(<\/?)(\w*)[. ]+(\/?>)/','/(<\/?)(\w*)[. ]+(\w*\/?>)/'),array('','',''),$xml);
我只在有 space 或句点时使用 preg_match 删除,但我想要的是删除句点 (.) 并将 space 替换为下划线 ( _) 即使标签和任何位置中有多个句点 or/and spaces。
我想要这个:
change:
<ItemNo.>12-34343-23</ItemNo.>
by:
<ItemNo>12-34343-23</ItemNo>
change:
<Shipping Agent>UPS</Shipping Agent>
by
<Shipping_Agent>UPS</Shipping_Agent>
change:
<Shipping Agent Service>Ground New</Shipping Agent Service>
by
<Shipping_Agent_Service>Ground New</Shipping_Agent_Service>
我不认为你会为此想出一个好的正则表达式。即使可以,空间也特别令人担忧。考虑以下有效节点:
<shipper name='baz' />
<shipper name='foo baz bang' />
<shipper name='foo.baz' />
<shipper.name />
与您要更正的节点相比:
<ship to name />
<ship. />
我想你想做的是想出一个正则表达式来匹配标签,比如
$xmlParts = preg_split("/<[^>]+>/", $xml);
然后您可以遍历 $xmlParts
。如果它匹配同一个正则表达式,它就是一个 XML 标签,您可以对其进行一些验证:检查它的空格是否应该替换为 _(因为它们不表示属性名称或值) , 如果 . 应该完全替换(因为它们不是属性值的一部分)。替换无效字符后,将其附加到新的 XML 变量。
如果它与正则表达式不匹配,则假定它是内容并附加它。
综上所述,如果您能得到任何为您提供此 "XML" 的东西,从而为您提供有效的 XML 开始...
嗯,我自己解决了这个问题,这是代码:
$xml='<?xml version="1.0" encoding="UTF-8"?>
<xmldata xmlns="http://some.uri.com">
<SalesHeader>
<DocType name="sample">Order</DocType>
<No>1002</No>
<SellToCustomerNo>CustNo</SellToCustomerNo>
<SellToCustomerName>Customer Name</SellToCustomerName>
<SellToCustomerName2 />
<SellToEmail>testemail@aol.com</SellToEmail>
<OrderDate>04/03/13</OrderDate>
<ExtDocNo />
<ShipToName>Customer Ship to</ShipToName>
<ShipToCountry />
<TaxLiable>No</TaxLiable>
<TaxAreaCode />
<RequestedDeliveryDate />
<Shipping Agent>UPS</Shipping Agent>
<Shipping Agent Service>Ground New</Shipping Agent Service>
<Tracking Numbers>123123212,1231231321</Tracking Numbers>
<SalesLine>
<ItemNo.>12-34343-23</ItemNo.>
<Description>Item Description</Description>
<Quantity>1</Quantity>
<UnitPrice>79.00</UnitPrice>
</SalesLine>
<SalesLine>
<ItemNo.>12-34343-23</ItemNo.>
<Description>Item Description</Description>
<Quantity>1</Quantity>
<UnitPrice>79.00</UnitPrice>
</SalesLine>
</SalesHeader>
</xmldata>';
function xmlcleaner($data){
try{
$xml_clean = preg_replace_callback('/(<\/?[^><]+\/?>)/',function($data){
return preg_replace(array('/\./','/\s(?!\/|\>|\w+=\S+)/'),array('','_'),$data[0]);
},$data['xml']);
if(!empty($data['head'])){
$xml_clean = preg_replace('/<\?.+\?>/','',$xml_clean);
$xml_clean = $data['head'].$xml_clean;
}
//now work with SimpleXMLElement
$result = new \SimpleXMLElement((string)$xml_clean);
return $result;
}catch(Exception $e){
return $e->getMessage();
}
}
$xml_clean = xmlcleaner(array(
'xml'=>$xml,
'head'=>'<?xml version="1.0" encoding="utf-8"?>'
));
print('<pre>');
print_r($xml_clean);
我假设您的 XML 文本具有明确的结构。在这种情况下,只有几个无效的元素名称,并且所有这些名称都是预先知道的。
您问题的最佳解决方案是创建替换列表(错误值 => 正确值)并使用 str_replace()
to fix your XML text before parsing it with simplexml_load_string()
or SimpleXMLElement
:
$replacements = array(
'<Shipping Agent>' => '<Shipping_Agent>',
'</Shipping Agent>' => '</Shipping_Agent>',
'<Shipping Agent Service>' => '<Shipping_Agent_Service>',
'</Shipping Agent Service>' => '</Shipping_Agent_Service>',
'<Tracking Numbers>' => '<Tracking_Numbers>',
'</Tracking Numbers>' => '</Tracking_Numbers>',
'<ItemNo.>' => '<ItemNo>',
'</ItemNo.>' => '</ItemNo>',
);
$xml = str_replace(array_keys($replacements), array_values($replacements), $xml);
$result = new \SimpleXMLElement($xml);
为什么这是最好的解决方案?
- 其他程序员一看就知道对输入字符串进行了哪些修改。
- 它不会给错误留下任何余地。如果输入字符串的格式发生变化(出现新的格式错误的元素名称),很容易添加错误的开始和结束标记及其正确形式,并且代码运行没有问题,不需要仔细测试。假设一个新的无效元素名称以不同的方式打破有效 XML 格式化规则出现在输入字符串中。更改
regex
-es 需要密切关注和广泛测试。
- 它比你的函数
xmlcleaner()
运行得快得多,因为它只调用 str_replace()
而 xmlcleaner()
调用 preg_replace()
多次; preg_replace()
is slower than str_replace()
开头。
我有一个 xml,其中标签可以在元素中包含一个、两个或多个 space 和句点 (.)。
the xml:
$xml='<?xml version="1.0" encoding="UTF-8"?>
<xmldata>
<SalesHeader>
<DocType>Order</DocType>
<No>1002</No>
<SellToCustomerNo>CustNo</SellToCustomerNo>
<SellToCustomerName>Customer Name</SellToCustomerName>
<SellToCustomerName2 />
<SellToEmail>testemail@aol.com</SellToEmail>
<OrderDate>04/03/13</OrderDate>
<ExtDocNo />
<ShipToName>Customer Ship to</ShipToName>
<ShipToCountry />
<TaxLiable>No</TaxLiable>
<TaxAreaCode />
<RequestedDeliveryDate />
<Shipping Agent>UPS</Shipping Agent>
<Shipping Agent Service>Ground New</Shipping Agent Service>
<Tracking Numbers>123123212,1231231321</Tracking Numbers>
<SalesLine>
<ItemNo.>12-34343-23</ItemNo.>
<Description>Item Description</Description>
<Quantity>1</Quantity>
<UnitPrice>79.00</UnitPrice>
</SalesLine>
<SalesLine>
<ItemNo.>12-34343-23</ItemNo.>
<Description>Item Description</Description>
<Quantity>1</Quantity>
<UnitPrice>79.00</UnitPrice>
</SalesLine>
</SalesHeader>
</xmldata>';
我的代码:
preg_replace(array('/(<\/?)[. ]+(\w*)(\/?>)/','/(<\/?)(\w*)[. ]+(\/?>)/','/(<\/?)(\w*)[. ]+(\w*\/?>)/'),array('','',''),$xml);
我只在有 space 或句点时使用 preg_match 删除,但我想要的是删除句点 (.) 并将 space 替换为下划线 ( _) 即使标签和任何位置中有多个句点 or/and spaces。
我想要这个:
change:
<ItemNo.>12-34343-23</ItemNo.>
by:
<ItemNo>12-34343-23</ItemNo>
change:
<Shipping Agent>UPS</Shipping Agent>
by
<Shipping_Agent>UPS</Shipping_Agent>
change:
<Shipping Agent Service>Ground New</Shipping Agent Service>
by
<Shipping_Agent_Service>Ground New</Shipping_Agent_Service>
我不认为你会为此想出一个好的正则表达式。即使可以,空间也特别令人担忧。考虑以下有效节点:
<shipper name='baz' />
<shipper name='foo baz bang' />
<shipper name='foo.baz' />
<shipper.name />
与您要更正的节点相比:
<ship to name />
<ship. />
我想你想做的是想出一个正则表达式来匹配标签,比如
$xmlParts = preg_split("/<[^>]+>/", $xml);
然后您可以遍历 $xmlParts
。如果它匹配同一个正则表达式,它就是一个 XML 标签,您可以对其进行一些验证:检查它的空格是否应该替换为 _(因为它们不表示属性名称或值) , 如果 . 应该完全替换(因为它们不是属性值的一部分)。替换无效字符后,将其附加到新的 XML 变量。
如果它与正则表达式不匹配,则假定它是内容并附加它。
综上所述,如果您能得到任何为您提供此 "XML" 的东西,从而为您提供有效的 XML 开始...
嗯,我自己解决了这个问题,这是代码:
$xml='<?xml version="1.0" encoding="UTF-8"?>
<xmldata xmlns="http://some.uri.com">
<SalesHeader>
<DocType name="sample">Order</DocType>
<No>1002</No>
<SellToCustomerNo>CustNo</SellToCustomerNo>
<SellToCustomerName>Customer Name</SellToCustomerName>
<SellToCustomerName2 />
<SellToEmail>testemail@aol.com</SellToEmail>
<OrderDate>04/03/13</OrderDate>
<ExtDocNo />
<ShipToName>Customer Ship to</ShipToName>
<ShipToCountry />
<TaxLiable>No</TaxLiable>
<TaxAreaCode />
<RequestedDeliveryDate />
<Shipping Agent>UPS</Shipping Agent>
<Shipping Agent Service>Ground New</Shipping Agent Service>
<Tracking Numbers>123123212,1231231321</Tracking Numbers>
<SalesLine>
<ItemNo.>12-34343-23</ItemNo.>
<Description>Item Description</Description>
<Quantity>1</Quantity>
<UnitPrice>79.00</UnitPrice>
</SalesLine>
<SalesLine>
<ItemNo.>12-34343-23</ItemNo.>
<Description>Item Description</Description>
<Quantity>1</Quantity>
<UnitPrice>79.00</UnitPrice>
</SalesLine>
</SalesHeader>
</xmldata>';
function xmlcleaner($data){
try{
$xml_clean = preg_replace_callback('/(<\/?[^><]+\/?>)/',function($data){
return preg_replace(array('/\./','/\s(?!\/|\>|\w+=\S+)/'),array('','_'),$data[0]);
},$data['xml']);
if(!empty($data['head'])){
$xml_clean = preg_replace('/<\?.+\?>/','',$xml_clean);
$xml_clean = $data['head'].$xml_clean;
}
//now work with SimpleXMLElement
$result = new \SimpleXMLElement((string)$xml_clean);
return $result;
}catch(Exception $e){
return $e->getMessage();
}
}
$xml_clean = xmlcleaner(array(
'xml'=>$xml,
'head'=>'<?xml version="1.0" encoding="utf-8"?>'
));
print('<pre>');
print_r($xml_clean);
我假设您的 XML 文本具有明确的结构。在这种情况下,只有几个无效的元素名称,并且所有这些名称都是预先知道的。
您问题的最佳解决方案是创建替换列表(错误值 => 正确值)并使用 str_replace()
to fix your XML text before parsing it with simplexml_load_string()
or SimpleXMLElement
:
$replacements = array(
'<Shipping Agent>' => '<Shipping_Agent>',
'</Shipping Agent>' => '</Shipping_Agent>',
'<Shipping Agent Service>' => '<Shipping_Agent_Service>',
'</Shipping Agent Service>' => '</Shipping_Agent_Service>',
'<Tracking Numbers>' => '<Tracking_Numbers>',
'</Tracking Numbers>' => '</Tracking_Numbers>',
'<ItemNo.>' => '<ItemNo>',
'</ItemNo.>' => '</ItemNo>',
);
$xml = str_replace(array_keys($replacements), array_values($replacements), $xml);
$result = new \SimpleXMLElement($xml);
为什么这是最好的解决方案?
- 其他程序员一看就知道对输入字符串进行了哪些修改。
- 它不会给错误留下任何余地。如果输入字符串的格式发生变化(出现新的格式错误的元素名称),很容易添加错误的开始和结束标记及其正确形式,并且代码运行没有问题,不需要仔细测试。假设一个新的无效元素名称以不同的方式打破有效 XML 格式化规则出现在输入字符串中。更改
regex
-es 需要密切关注和广泛测试。 - 它比你的函数
xmlcleaner()
运行得快得多,因为它只调用str_replace()
而xmlcleaner()
调用preg_replace()
多次;preg_replace()
is slower thanstr_replace()
开头。