Simplexml Insert into sub element - simplexml

i have an xml file same bellow:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<prod id="1">
<layer id="layer_0" imgSRC="data/361_layer_0.png"/>
<layer id="layer_1" imgSRC="data/362_layer_0.png"/>
<layer id="layer_2" imgSRC="data/363_layer_0.png"/>
</prod>
<prod id="2">
<layer id="layer_0" imgSRC="data/361_layer_0.png"/>
<layer id="layer_1" imgSRC="data/362_layer_0.png"/>
<layer id="layer_2" imgSRC="data/363_layer_0.png"/>
</prod>
</data>
how to use simplexml to insert an item into layer id="layer_3" like bellow example:
<prod id="1">
<layer id="layer_0" imgSRC="data/361_layer_0.png"/>
<layer id="layer_1" imgSRC="data/362_layer_0.png"/>
<layer id="layer_2" imgSRC="data/363_layer_0.png"/>
<layer id="layer_3" imgSRC="data/364_layer_0.png"/>
</prod>
what do i have to do?
Thanks!!

(1) select the node that will be the parent of the new child, I'd go with xpath:
$xml = simplexml_load_string($x); // assuming XML in $x
$node = $xml->xpath("//prod[#id='2']/layer[#id='layer_2']")[0];
xpath will select all <layer> nodes with id=layer_2 that have <prod> with id=2 as a parent. In case there are several results, the [0] will select just the first one. This works with PHP >= 5.4.
see this working: http://3v4l.org/5Q46F
(2) then add the child and its attributes, see example #10 in the simplexml manual:
http://www.php.net/manual/en/simplexml.examples-basic.php

Related

Find element name via case-insensitive search

Given the following three pieces of XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<body>
<customerSearchRequest>
<id>1234</id>
</customerSearchRequest>
</body>
</root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<BODY>
<userSearchRequest>
<id>5678</id>
</userSearchRequest>
</BODY>
</root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<Body>
<orderSearchRequest>
<id>9101</id>
</orderSearchRequest>
</Body>
</root>
I need to extract the name of the first-child of body (i.e. customerSearchRequest, userSearchRequest and orderSearchRequest), which I am currently doing as follows:
name(//SOAP-ENV:body/*[1])
The problem is, this only works for the first request as body is case-sensitive. How do I make the path case-insensitive?
Thanks for any pointers.
I would go with this :
name(//SOAP-ENV:*[translate(local-name(),'BODY','body')='body']/*[1])
The following part first finds elements in namespace of SOAP-ENV, and then filter to those with local-name equals 'body', case-insensitive :
//SOAP-ENV:*[translate(local-name(),'BODY','body')='body']
If you have XPath 2.0 available, it can be done in a cleaner way using lower-case(), upper-case(), or regex based functions like matches() : case-insensitive matching in xpath?

XPath: Select element which has specific attribute with special character

<document>
<element>
<attribut a:name="my-name">My Name</attribut>
<attribut a:parent="parent1">Parent 1</attribut>
</element>
</document>
In this XML document, how to select the node which has the attribut a:name ?
$xmlTest = <<<XML
<?xml version="1.0" encoding="UTF-8" ?>
<document xmlns:a="http://example.org/a">
<element>
<attribut a:name="my-name">My Name</attribut>
<attribut a:parent="parent1">Parent 1</attribut>
</element>
</document>
XML;
$xml = new SimpleXMLElement($xmlTest);
echo current($xml->xpath('//element/attribut[#a:name]'));

How do i display an image instead of text for a ? on an xml form for ODK collect?

Since odk collect uses utf-8, the language that i would like the questions of the form to be in would be displayed one character at a time vs. conjoined. instead of displaying text for the question, i want the question to display an image which will be on the question text formatted properly. Is there anyway this can be done, are there any good tutorials or information out there that can help me accomplish this?
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa">
<h:head>
<h:title>firstform</h:title>
<model>
<instance>
<data id="build_firstform_1375472795">
<meta>
<instanceID/>
</meta>
<field_name/>
<field_age/>
<field_location/>
</data>
</instance>
<itext>
<translation lang="eng">
<text id="/data/field_name:label">
<value>**<img src="Q1.png" >**</value>
</text>
<text id="/data/field_name:hint">
<value>What is your name (last, first)?</value>
</text>
the bolded code did not work.
<?xml version="1.0" encoding="UTF-8"?>
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:jr="http://openrosa.org/javarosa" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><h:head xmlns="">
<h:title>images</h:title><model>
<instance>
<data id="1">
<some_text/>
<image_test/>
</data>
</instance>
<itext>
<translation lang="eng">
<text id="/data/image_test:label">
<value>picture test</value>
</text>
<text id="/data/image_test:a">
<value form="image">jr://images/p1.jpg</value>
</text>
<text id="/data/image_test:b">
<value form="image">jr://images/p2.jpg</value>
</text>
</translation>
</itext>
<bind nodeset="/data/image_test" type="select1"/>
</model>
</h:head>
<h:body xmlns="">
<select1 ref="/data/image_test">
<label ref="jr:itext('/data/image_test:label')"/>
<item>
<label ref="jr:itext('/data/image_test:a')"/>
<value>a</value>
</item>
<item>
<label ref="jr:itext('/data/image_test:b')"/>
<value>b</value>
</item>
<item>
<label ref="jr:itext('/data/image_test:c')"/>
<value>c</value>
</item>
</select1>
</h:body>
</h:html>

Getting data from xml by attribute value C# using XmlTextReader

I have a file with the following content (myfile.xml). I have to get all content coming under (including product node) a product with id=1.
<products>
<product id="1">
<category>q</category>
</product>
<product id="2">
<category>w</category>
</product>
<product id="3">
<category>e</category>
</product>
</products>`
i.e. the result should be :
<product id="1">
<category>q</category>
</product>
How can I do this?
I have the restriction that I should use XmlTextReader or XPathNavigator only for this, otherwise I could have used this : Getting data from xml by attribute vlaue
Wouldn't XmlReader.GetAttribute() work?
http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.getattribute(v=vs.100)
Add in some Skip() to move the iterator:
http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.skip(v=vs.100)

Xpath: Select node but not specific child elements

I have a structure similar to the following:
<page id='1'>
<title>Page 1</title>
<page id='2'>
<title>Sub Page 1</title>
</page>
<page id='3'>
<title>Sub Page 2</title>
</page>
</page>
<page id='4'>
<title>Page 2</title>
</page>
I need to select a page by Id but if that page has descendant pages I don't want to return those elements, but I do want the other elements of that page. If I select Page 1 I want to return title but not the child pages...
//page[#id=1]
The above gets me page 1, but how do I exclude the sub pages? Also, There could be any arbitrary number of elements in a page.
//page[#id=1]/*[not(self::page)]
I have found that this gets me the data I want. However, that data comes back as an array of objects with one object per element and apparently excludes the element names???. I am using PHP SimpleXML for what it is worth.
Use:
//page[#id=$yourId]/node()[not(self::page)]
This selects all nodes that are not page and that are children of any page in the document, the string value of whose id attribute is equal to the string contained in $yourId (most probably you would substitute $yourId above with a specific, desired string, such as '1').
Here is a simple XSLT-based verification:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pId" select="3"/>
<xsl:template match="/">
<xsl:copy-of select="//page[#id=$pId]/node()[not(self::page)]"/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document (wrapped in a single top node to make it well-formed):
<pages>
<page id='1'>
<title>Page 1</title>
<page id='2'>
<title>Sub Page 1</title>
</page>
<page id='3'>
<title>Sub Page 2</title>
</page>
</page>
<page id='4'>
<title>Page 2</title>
</page>
</pages>
the wanted, correct result is produced:
<title>Sub Page 2</title>
Do note: One assumption made is that an id value uniquely identifies a page. If this is not so, the proposed XPath expression will select all page elements whose id attribute has a string valu of $yourId.
If this is the case and only one page element must be selected, the OP must specify which one of the many page elements with this id should be selected.
For example, it may be the first:
(//page[#id=$yourId]/node()[not(self::page)])[1]
or the last:
(//page[#id=$yourId]/node()[not(self::page)])[last()]
or ...
If you're only interested in the title element, this would work:
//page[#id=1]/title
If however you need other sub elements of page, I'm not sure XPath is the right tool for you.
Sounds more like something that an XSLT would be suited for, since what you are really doing is transforming your data.
If the page always has a title:
//page[#id='1']/*[not(boolean(./title))]

Resources