I have the following data
<Table>
<Row>
<Cell><Data>Row Labels</Data></Cell>
<Cell><Data>Searches</Data></Cell>
<Cell><Data>Purchases</Data></Cell>
<Cell><Data>CRatio</Data></Cell>
<Cell><Data>AvgReturn</Data></Cell>
<Cell><Data>Commission</Data></Cell>
</Row>
<Row>
<Cell><Data>2013</Data></Cell>
<Cell><Data>2257224</Data></Cell>
<Cell><Data>18574</Data></Cell>
<Cell><Data>8.2286915255198427E-3</Data></Cell>
<Cell><Data>43.459007223015384</Data></Cell>
<Cell><Data>102390.82995242</Data></Cell>
</Row>
<Row>
<Cell><Data>2014</Data></Cell>
<Cell><Data>5351610</Data></Cell>
<Cell><Data>43035</Data></Cell>
<Cell><Data>8.0415052666393851E-3</Data></Cell>
<Cell><Data>40.420168915503282</Data></Cell>
<Cell><Data>280677.31032664998</Data></Cell>
</Row>
<Row>
<Cell><Data>Grand Total</Data></Cell>
<Cell><Data>7608834</Data></Cell>
<Cell><Data>61609</Data></Cell>
<Cell><Data>8.0970356299007173E-3</Data></Cell>
<Cell><Data>41.336323742293686</Data></Cell>
<Cell><Data>383068.14027907007</Data></Cell>
</Row>
Whats the best way using XPath to get one of data at a time of data and then to get at indiviual elements in that
I have tried the following ...
enter NSArray *rowNodes = [doc nodesForXPath:#"/Table/Row" error:&error];
BOOL doBreak = NO;
#try {
int iRow = 0;
for (GDataXMLElement *rowNode in rowNodes) {
iRow++;
//get cell elements of the row
NSArray* rowCellNodes = [rowNode nodesForXPath:#"//Cell/Data" error:&error];
However when I do this I get the rowNodes correctly, but then I get no results for rowCellNodes in the for loop.
Try to add a dot at the beginning of the 2nd XPath to make it recognized as relative XPath to current rowNode :
NSArray* rowCellNodes = [rowNode nodesForXPath:#".//Cell/Data" error:&error];
Related
I need to read big xml file in Microsoft Visual FoxPro 9 SP2 desktop application.
Created cursor result which contains desired columns and convert.xsl file to transform xml to format readably by xmltocursor.
Tried
source = CreateObject('MSXML.Domdocument')
stylesheet = CreateObject('MSXML.Domdocument')
resultDoc = CreateObject('MSXML.Domdocument')
resultDoc.validateOnParse = .t.
stylesheet.load('convert.xsl')
source.load( 'bigxml.xml' )
source.transformNodeToObject(stylesheet, #resultDoc)
* Exception code=E06D7363
IF XMLToCursor(resultDoc.xml, 'result', 8192 )=0
But got
Fatal exception
Exception code=E06D7363
at line
IF XMLToCursor(resultDoc.xml, 'result', 8192 )=0
and application terminates.
How to convert big xml file to cursor ?
XSL is:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="yes"/>
<!-- this replaces root tag with VFPData which is required from CursorToXML to work properly -->
<xsl:template match="/">
<xsl:element name="VFPData">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<!-- this will denormalize XML data -->
<xsl:template match="/ettevotjad/ettevotja">
<xsl:element name="Document-Ariregister">
<xsl:element name="nimi">
<xsl:value-of select="nimi"/>
</xsl:element>
<xsl:element name="ariregistr">
<xsl:value-of select="ariregistri_kood"/>
</xsl:element>
<xsl:element name="kmkr_nr">
<xsl:value-of select="kmkr_nr"/>
</xsl:element>
<xsl:element name="ettevotja_">
<xsl:value-of select="ettevotja_staatus"/>
</xsl:element>
<xsl:element name="asukoht_et">
<xsl:value-of select="ettevotja_aadress/asukoht_ettevotja_aadressis"/>
</xsl:element>
<xsl:element name="asukoha_e2">
<xsl:value-of select="ettevotja_aadress/asukoha_ehak_tekstina"/>
</xsl:element>
<xsl:element name="indeks_ett">
<xsl:value-of select="ettevotja_aadress/indeks_ettevotja_aadressis"/>
</xsl:element>
</xsl:element>
</xsl:template>
<!-- to ommit nodes data -->
<xsl:template match="text()">
</xsl:template>
<!-- to work over every node -->
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
Here is a solution using mxml.6.0., no need for xs file:
* requires msxml.6.0! ( https://www.microsoft.com/es-es/download/details.aspx?id=3988 )
*
Parameters fileName,xPath
fileName = "D:\Data\Xml\ettevotja_rekvisiidid_2021-01-27.xml"
xPath = '/ettevotjad'
xPath = RTRIM(m.xPath,1,'/')
Private All
oxml = Createobject('msxml2.domDocument.6.0')
Wait 'loading document...' Window Nowait
With oXml As msxml.DOMDocument
.Load(Fullpath(m.fileName))
Wait Clear
If .parseError.errorCode # 0
Messagebox(.parseError.reason,16)
Return
Endif
Endwith
Close Tables All
nsteps = 500
tini = Seconds()
Set Escape On
x = 1
DO WHILE .t.
subset = oXml.selectNodes(Textmerge(m.xPath+'/*[ position() >= <<m.x>> and position() < <<m.x+m.nsteps>> ]'))
IF subset.length = 0
EXIT
ENDIF
cXml = ''
For Y = 1 To subset.Length
m.cXml = m.cXml + subset.Item(m.y-1).XML
ENDFOR
x = m.x + subset.Length
Wait Textmerge('<<m.x-1>> records << (m.x-1) / (SECONDS() - m.tini) >> records/sec ') Window nowait
cXml = '<xml encoding="windows-1252">'+m.cXml+'</xml>'
Xmltocursor(m.cXml,'xmlImport',Iif(Used('xmlImport'),4+8192,0))
ENDDO
Browse Normal Font 'consolas,8'
I like Marco's solution for at least it is in VFP. However, having big XML files like this, I would also care about performance. I tried with Marco's code and it took 80+ seconds to complete and may need some work if you really want those fields separated as in your XSL.
I tried, reading from that XML, transforming based on your XSL and writing to an SQLite database using C#. It took 7.2 seconds and those address lines were already separated.
Here is C# code if you would use anyway:
void Main()
{
string dataFile = #"d:\Andrus\bigdata.sqlite";
string constr = $"Data Source={dataFile}";
Stopwatch sw = new Stopwatch();
sw.Start();
if (!File.Exists(dataFile))
{
CreateDatabase(constr);
}
InsertData(constr, #"d:\Andrus\bigxml.xml");
sw.Stop();
sw.Dump("Duration");
}
void InsertData(string connectionString, string xmlFile)
{
using (SQLiteConnection conn = new SQLiteConnection(connectionString))
using (SQLiteCommand sql = new SQLiteCommand(#"insert into MyData
(nimi, ariregistr, asukoht_et, asukoha_e2, indeks_ett, kmkr_nr)
values
(?,?,?,?,?,?)", conn))
{
sql.Parameters.AddWithValue("nimi", "");
sql.Parameters.AddWithValue("ariregistr", 0);
sql.Parameters.AddWithValue("asukoht_et", "");
sql.Parameters.AddWithValue("asukoha_e2", "");
sql.Parameters.AddWithValue("indeks_ett", "");
sql.Parameters.AddWithValue("kmkr_nr", "");
conn.Open();
SQLiteTransaction transaction = conn.BeginTransaction();
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreWhitespace = true;
using (XmlReader r = XmlReader.Create(xmlFile, settings))
{
r.MoveToContent();
r.ReadStartElement("ettevotjad");
while (r.Name == "ettevotja")
{
XElement x = (XElement)XNode.ReadFrom(r);
string nimi = (string)x.Element("nimi");
int? ariregistr = (int?)x.Element("ariregistri_kood");
string asukoht_et = (string)x.Element("ettevotja_aadress").Element("asukoht_ettevotja_aadressis");
string asukoha_e2 = (string)x.Element("ettevotja_aadress").Element("asukoha_ehak_tekstina");
string indeks_ett = (string)x.Element("ettevotja_aadress").Element("indeks_ettevotja_aadressis");
string kmkr_nr = (string)x.Element("kmkr_nr");
///
sql.Parameters["nimi"].Value = nimi;
sql.Parameters["ariregistr"].Value = ariregistr;
sql.Parameters["asukoht_et"].Value = asukoht_et;
sql.Parameters["asukoha_e2"].Value = asukoha_e2;
sql.Parameters["indeks_ett"].Value = indeks_ett;
sql.Parameters["kmkr_nr"].Value = kmkr_nr;
sql.ExecuteNonQuery();
}
r.ReadEndElement();
}
transaction.Commit();
conn.Close();
}
}
void CreateDatabase(string connectionString)
{
using (SQLiteConnection conn = new SQLiteConnection(connectionString))
using (SQLiteCommand sql = new SQLiteCommand())
{
sql.CommandText = #"create table MyData (
nimi text,
ariregistr number null,
asukoht_et text,
asukoha_e2 text,
indeks_ett text,
kmkr_nr text
)";
sql.Connection = conn;
conn.Open();
sql.ExecuteNonQuery();
conn.Close();
}
}
PS: Code is run directly inside LinqPad.
I am trying to convert and XML to an XML using XSLT 2.0 in saxon/java. I am using a sample XML I found on stack overflow thread "Applying Muenchian grouping for a simple XML with XSLT"
However I am getting an error : XPDY0002: The context item for axis step ./CLIENT is absent.
My test XSL:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="CLIENTS" name="main">
<CLIENTS>
<xsl:for-each-group select="CLIENT" group-by="NAME">
<xsl:comment><xsl:value-of select="current-grouping-key()"/> </xsl:comment>
<CLIENT>
<xsl:sequence select="NAME" />
<xsl:for-each select="current-group()">
<ACCOUNT>
<xsl:sequence select="*[not(self::NAME)]" />
</ACCOUNT>
</xsl:for-each>
</CLIENT>
</xsl:for-each-group>
</CLIENTS>
</xsl:template>
</xsl:stylesheet>
My Test XML:
<CLIENTS>
<CLIENT>
<NAME>John</NAME>
<ACCOUNT_NUMBER>1424763562761</ACCOUNT_NUMBER>
<LAST_USED>2012-10-03</LAST_USED>
<AMOUNT>5000</AMOUNT>
</CLIENT>
<CLIENT>
<NAME>John</NAME>
<ACCOUNT_NUMBER>543667543732</ACCOUNT_NUMBER>
<LAST_USED>2012-10-02</LAST_USED>
<AMOUNT>10000</AMOUNT>
</CLIENT>
</CLIENTS>
My Java ( which works with other transforms) :
void xmlXSLTParser(){
String xslFile = commonPath + "/xslt/inputPointCSVTOXML_style2.xsl";
String inputFile = "file:///" + commonPath + pointWorkFile;
String outputFile = commonPath + pointWorkFile + ".final";
try {
Processor proc = new Processor(false);
XsltCompiler comp = proc.newXsltCompiler();
XsltExecutable exp = comp.compile(new StreamSource(new File(xslFile)));
Serializer out = new Serializer();
out.setOutputProperty(Serializer.Property.METHOD, "xml");
out.setOutputProperty(Serializer.Property.INDENT, "yes");
out.setOutputFile(new File(outputFile));
XsltTransformer trans = exp.load();
trans.setInitialTemplate(new QName("main"));
//trans.setParameter(new QName("url-of-csv"),new XdmAtomicValue(inputFile));
trans.setDestination(out);
trans.transform();
System.out.println("Output written to text file");
} catch (SaxonApiException e) {
println("XSLT Error :" + e );
}
}
}
My Error in detail:
Error at char 6 in xsl:for-each-group/#select on line 10 column 59 of inputPointCSVTOXML_style2.xsl:
XPDY0002: The context item for axis step ./CLIENT is absent
XSLT Error :net.sf.saxon.s9api.SaxonApiException: The context item for axis step ./CLIENT is absent
Your Java code does not set any context item, instead it sets an initial template. So you will need to make sure you provide the input XML as the context item to the XsltTransformer, using http://saxonica.com/html/documentation/javadoc/net/sf/saxon/s9api/XsltTransformer.html#setInitialContextNode(net.sf.saxon.s9api.XdmNode) or as a Source, using http://saxonica.com/html/documentation/javadoc/net/sf/saxon/s9api/XsltTransformer.html#setSource(javax.xml.transform.Source).
So instead of trans.setInitialTemplate(new QName("main")); use trans.setSource(new StreamSource(inputFile));.
I have a large xsl:choose (i.e. ~100) where the xsl:when is testing using a regex. I'm looking for a cleaner way, can this be replaced with a lookup table? This is just a sample of my code looks like today
<xsl:when test="matches($seq4, '^\w+-\w+-\w+-\d+/NCell:.+$', 'i')">
<xsl:value-of select="'NEIGHBOR'"/>
</xsl:when>
<xsl:when test="matches($seq4, '(/ULoCell:NodeB Function Name=.*, Local Cell ID=.*)', 'i')">
<xsl:value-of select="'SECTOR'"/>
</xsl:when>
I appreciate the help and I think I can make the Map sample code work if I make it a separate XML file and use import or include. I'm just wonder how difficult it would be to convert this into a document lookup. I'm familiar with document lookup and keys, but I have no idea how I would code the lookup using a regex? I Have the following lookup document:
<Telsa xmlns:xs="http://www.w3.org/2001/XMLSchema">
<Row Key1="^[A-Z0-9]+/Cell:eNodeB Function Name=[A-Z0-9]+, Local Cell ID=[0-9]+, Cell Name=.*/CnOperator:CnOperatorId=[0-9]+$" ElementType="CELL_CORE_OPERATOR" RegexReplace="'^([A-Z0-9]+)/Cell:eNodeB Function Name=[A-Z0-9]+, Local Cell ID=([0-9]+), Cell Name=.*/CnOperator:(CnOperatorId=[0-9]+)', '$1/CELL:$2/$3'"></Row>
<Row Key1="^\w+-\w+-\w+-\d+/Cell:eNodeB Function Name=[A-Z0-9]+, Local Cell ID=[0-9]+, Cell Name=.*, eNodeB ID=[0-9]+, Cell.*$" ElementType="CELL" RegexReplace="'^\w+-\w+-\w+-\d+/Cell:eNodeB Function Name=([A-Z0-9]+), Local Cell ID=([0-9]+), Cell Name=.*, eNodeB ID=([0-9]+), Cell.*$', '$1/Cell:$2'"></Row>
<Row Key1="^\w+-\w+-\w+-\d+/EthernetInterface:Ethernet Interface No.=.*$" ElementType="EthernetInterface" RegexReplace="'^(\w+-\w+-\w+-\d+)/EthernetInterface:Ethernet Interface No.=([0-9]+)$' , '$1/No=$2'"></Row>
<Row Key1="^[A-Z0-9]+/CELL:Local cell identity=[0-9]+, Cell Name=.*/OPERATOR:CnOperatorId=[0-9]+$" ElementType="CELL_CORE_OPERATOR" RegexReplace="'^([A-Z0-9]+/CELL:)Local cell identity=([0-9]+), Cell Name=.*/OPERATOR:(CnOperatorId=[0-9]+)' , '$1$2/$3'"></Row>
<Row Key1="^[A-Z0-9]+/Cell:Local cell identity=[0-9]+, Cell Name=.*, eNodeB identity=[0-9]+$" ElementType="CELL" RegexReplace="'^([A-Z0-9]+/Cell:)Local cell identity=([0-9]+), Cell Name=.*, eNodeB identity=[0-9]+$', '$1$2'"></Row>
<Row Key1="^[A-Z0-9]+/Cell:eNodeB Function Name=[A-Z0-9]+, Local Cell ID=[0-9]+, Cell Name=.*, eNodeB ID=[0-9]+$" ElementType="CELL" RegexReplace="'^([A-Z0-9]+)/Cell:eNodeB Function Name=[A-Z0-9]+, Local Cell ID=([0-9]+), Cell Name=.*, eNodeB ID=([0-9]+)$', '$1/Cell:$2'"></Row>
<Row Key1="^[A-Z0-9]+/Cell:eNodeB Function Name=[A-Z0-9]+, Local Cell ID=[0-9]+, Cell Name=.*, eNodeB ID=[0-9]+$" ElementType="CELL" RegexReplace="'^([A-Z0-9]+)/Cell:eNodeB Function Name=[A-Z0-9]+, Local Cell ID=([0-9]+), Cell Name=.*, eNodeB ID=([0-9]+)$', '$1/Cell:$2'"></Row>
</Telsa>
I would define the lookup with
<xsl:key name="table-lookup" match="Row" use="#Key1"/>
<xsl:variable name="LookupDoc" select="document('Telsa.xml')/Telsa"/>
How do I code the key lookup though?
<xsl:value-of select="key('table-lookup', $curr_key, $LookupDoc)/#ElementType"/>
Perhaps the following is what you are looking for, it stores the regular expressions, flags, and result in an XML structure and then looks up the first matching element:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:param name="pattern-map" as="element(map)*">
<map pattern="^\w+-\w+-\w+-\d+/NCell:.+$" flags="i">NEIGHBOR</map>
<map pattern="(/ULoCell:NodeB Function Name=.*, Local Cell ID=.*)" flags="i">SECTOR</map>
</xsl:param>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:copy>
<xsl:value-of select="$pattern-map[matches(current(), #pattern, #flags)][1]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When run against
<root>
<item>a-b-c-1/NCell:x</item>
<item>/ULoCell:NodeB Function Name=x, Local Cell ID=.y</item>
</root>
the output is
<root>
<item>NEIGHBOR</item>
<item>SECTOR</item>
</root>
Be careful if your regular expressions contain curly braces { or } as with a literal result element like <map pattern="\w{2}" flags="i">foo</map> this would be interpreted as an attribute value template so you would need to double them as in <map pattern="\w{{2}}" flags="i">foo</map>.
I like this solution, the only other question is can this logic be placed into an external document much like the lookup table?
I would like to fetch specific data in JSON Data : every links in href in this markup <div id='gallery-1'
For example with my JSON Data :
<p><strong style=\"font-size: 13px;\">22nd March</strong></p>\n
<p>Swell is 3 foot and clean but wind swing south west later. Get on the early</p>\n
<p><span id=\"more-113\"></span></p>\n
<p>High tide: 1922 2.6m <span style=\"color: #ff0000;\"> <a href=\"http://www.bundoransurfco.com/webcam/\">
<strong>CLICK HERE FOR LIVE PEAK WEBCAM</strong></a></span></p>\n
<p>Low Tide: 1249 -0.1m</p>\n<p><b>3 day forecast to March 23rd</b></p>\n
<p>Looks like a fun few days with light winds and a long period swell.</p>\n\n\t\t
<style type='text/css'>\n\t\t\t#gallery-1 {\n\t\t\t\tmargin: auto;\n\t\t\t}\n\t\t\t
#gallery-1 .gallery-item {\n\t\t\t\tfloat: left;\n\t\t\t\tmargin-top: 10px;\n\t\t\t\t
text-align: center;\n\t\t\t\twidth: 50%;\n\t\t\t}\n\t\t\t#gallery-1 img {\n\t\t\t\t
border: 2px solid #cfcfcf;\n\t\t\t}\n\t\t\t
#gallery-1 .gallery-caption {\n\t\t\t\t
margin-left: 0;\n\t\t\t}\n\t\t\t
/* see gallery_shortcode() in wp-includes/media.php */\n\t\t</style>\n\t\t
<div id='gallery-1' class='gallery galleryid-113 gallery-columns-2 gallery-size-medium'>
<dl class='gallery-item'>\n\t\t\t<dt class='gallery-icon portrait'>\n\t\t\t\t
<a rel=\"prettyPhoto[gallery-113]\" href='http://www.bundoransurfco.com/wp-content/uploads/2014/11/10411096_10152611456607000_886839954460588268_n.jpg'>
<img width=\"225\" height=\"300\" src=\"http://www.bundoransurfco.com/wp-content/uploads/2014/11/10411096_10152611456607000_886839954460588268_n-225x300.jpg\"
class=\"attachment-medium colorbox-113 \" alt=\"10411096_10152611456607000_886839954460588268_n\" /></a>\n\t\t\t
</dt></dl>\n\t\t\t
<br style='clear: both' />\n\t\t</div>\n\n
<p> </p>\n
<h1> Wind Charts</h1>\n<p><a href=\"http://www.windguru.cz/int/index.php?sc=103244\">
<img class=\"size-thumbnail wp-image-747 alignleft\" title=\"wind guru\" src=\"http://www.bundoransurfco.com/wp-content/uploads/2010/12/wind-guru-67x68.jpg\" alt=\"\" width=\"67\" height=\"68\" /></a> <img class=\"alignnone size-thumbnail wp-image-749\" title=\"xcweathersmall\" src=\"http://www.bundoransurfco.com/wp-content/uploads/2010/12/xcweathersmall2-67x68.jpg\" alt=\"\" width=\"67\" height=\"68\" /> <img class=\"alignnone size-thumbnail wp-image-750\" title=\"buoy weather\" src=\"http://www.bundoransurfco.com/wp-content/uploads/2010/12/buoy-weather-67x68.jpg\" alt=\"\" width=\"67\" height=\"68\" /> Wind Guru XC Weather Buoy Weather</p>\n<h1>Swell Charts</h1>\n<p><img class=\"alignnone size-thumbnail wp-image-753\" title=\"msw logo\" src=\"http://www.bundoransurfco.com/wp-content/uploads/2010/12/msw-logo-67x43.jpg\" alt=\"\" width=\"75\" height=\"43\" /> <img class=\"alignnone size-thumbnail wp-image-754\" title=\"magicseaweedwamchart\" src=\"http://www.bundoransurfco.com/wp-content/uploads/2010/12/magicseaweedwamchart1-67x68.png\" alt=\"\" width=\"67\" height=\"68\" /> <img class=\"alignnone wp-image-755 size-thumbnail\" title=\"marine institute irish bouy data\" src=\"http://www.bundoransurfco.com/wp-content/uploads/2010/12/marine-institute-irish-bouy-data-67x42.jpg\" alt=\"\" width=\"67\" height=\"42\" /> Magic Seaweed MSM WAM Marine Institute</p>\n<h1>Pressure, Weather, Tides</h1>\n<p><img class=\"alignnone size-thumbnail wp-image-756\" title=\"bbc pressure\" src=\"http://www.bundoransurfco.com/wp-content/uploads/2010/12/bbc-pressure-67x68.jpg\" alt=\"\" width=\"67\" height=\"68\" /> <img class=\"alignnone size-thumbnail wp-image-759\" title=\"met eireann\" src=\"http://www.bundoransurfco.com/wp-content/uploads/2010/12/met-eireann-67x68.jpg\" alt=\"\" width=\"67\" height=\"68\" /> BBC Pressure Met Eireann Irish Tide Tables</p>\n
Fetch only : http://www.bundoransurfco.com/wp-content/uploads/2014/11/10411096_10152611456607000_886839954460588268_n.jpg
I used <a.+?href=\"([^\"]+) before for fetching every href in <a> markup, but that's not what I want ...
Assuming your div is a string and there is only one href, you can use this code instead of a regex to get the start and stop locations of the href.
NSRange range = [divString rangeOfString:#"href"]; // start
[divString rangeOfString:#">" options:0 range:NSMakeRange(range.location, 100)]; // end (if your href is long you can replace 100 with something greater)
Then use divString substringWithRange: to get the portion you are interested in
Here's the solution based on answer of Alex. Works for multiple hrefs in single string:
NSString *target = #"<div id='gallery-1' class='gallery galleryid-113 gallery-columns-2 gallery-size-medium'><dl class='gallery-item'>\n\t\t\t<dt class='gallery-icon portrait'>\n\t\t\t\t<a rel=\"prettyPhoto[gallery-113]\" href='http://www.bundoransurfco.com/wp-content/uploads/2014/11/10411096_10152611456607000_886839954460588268_n.jpg'><img width=\"225\" height=\"300\" href='http://www.bundoransurfco.com/wp-content/uploads/2014/11/10411096_10152611456607000_886839954460588268_n-225x300.jpg' class=\"attachment-medium colorbox-113 \" alt=\"10411096_10152611456607000_886839954460588268_n\" /></a>\n\t\t\t</dt></dl>\n\t\t\t<br style='clear: both' />\n\t\t</div>";
NSMutableArray *hrefs = [NSMutableArray array];
NSRange hrefRange = NSMakeRange(0, 0);
while (hrefRange.location != NSNotFound){
hrefRange = [target rangeOfString:#"href='"
options:0
range:NSMakeRange(hrefRange.location, target.length - (hrefRange.location + hrefRange.length))];
if (hrefRange.location == NSNotFound) {
NSLog(#"Thats all");
continue;
}
NSRange endRange = [target rangeOfString:#"'"
options:0
range:NSMakeRange(hrefRange.location + hrefRange.length, target.length - (hrefRange.location + hrefRange.length))];
NSString *href = [target substringWithRange:NSMakeRange((hrefRange.location+hrefRange.length), endRange.location - (hrefRange.location + hrefRange.length))];
[hrefs addObject:href];
hrefRange.location = hrefRange.location+hrefRange.length;
}
This implementation, as you can see, is sensitive to quotes (single- or double-quoted href value).
P.S. May look kinda messy, its fast-coded and tested.
EDIT:
Here's also a variant with regular expression, but works only with a tag, and also be careful with quotes:
NSError *error;
NSString *target = #"<div id='gallery-1' class='gallery galleryid-113 gallery-columns-2 gallery-size-medium'><dl class='gallery-item'>\n\t\t\t<dt class='gallery-icon portrait'>\n\t\t\t\t<a rel=\"prettyPhoto[gallery-113]\" href=\"http://www.bundoransurfco.com/wp-content/uploads/2014/11/10411096_10152611456607000_886839954460588268_n.jpg\"><img width=\"225\" height=\"300\" href=\"http://www.bundoransurfco.com/wp-content/uploads/2014/11/10411096_10152611456607000_886839954460588268_n-225x300.jpg\" class=\"attachment-medium colorbox-113 \" alt=\"10411096_10152611456607000_886839954460588268_n\" /></a>\n\t\t\t</dt></dl>\n\t\t\t<br style='clear: both' />\n\t\t</div>";
NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern:#"<[a|img]\\s+(?:[^>]*?\\s+)?href=\"([^\"]*)\""
options:0
error:&error];
NSArray *array = [regEx matchesInString:target
options:0
range:NSMakeRange(0, target.length)];
for (NSTextCheckingResult *match in array){
NSRange range = [match rangeAtIndex:1];
NSString *result = [target substringWithRange:range];
NSLog(#"HREF = %#", result);
}
I also edited first variant to save all hrefs into array.
I have an xml file which i create myself.
<?xml version='1.0' encoding='utf-8' ?>
<Root>
<ChildElements>
<type name='xx' attr='false'>
<child id='1' regex='^[0-9]{11}$'>
<BBB>
<node1 name='aaa' regex='\w{5}'/>
<node2 name='bbb' regex='\w{3}'/>
</BBB>
</child>
<child>
.
.
.
</child>
</type>
</ChildElements>
</Root>
Something like this. I want to parse it to xml document object and iterate through its nodes, I'm using libxml2 for ios.
NSString *xmlPath = [[NSBundle mainBundle] pathForResource:#"xmlcontent" ofType:#"xml"];
NSData *xmlData = [NSData dataWithContentsOfFile:xmlPath];
NSString* xml = [[NSString alloc ] initWithData:xmlData encoding:NSUTF8StringEncoding];
int size=[xml lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
xmlDocPtr docptr=xmlParseMemory([xml UTF8String], size);
but in docptr object there is only one node, which is Root node, and when I try to get Root node child nodes it returns an empty node which name is #"text".
NSXMLParser easily parses the same XML, but I don't know how to create a document and iterate through nodes by using NSXMLParser.
maybe the error is, that your XML isn't valide:
<?xml version='1.0' encoding='utf-8' ?>
<Root>
<ChildElements>
<type name='xx' attr='false' />
<child id='1' regex='^[0-9]{11}$'>
<BBB>
<node1 name='aaa' regex='w{5}' />
<node2 name='bbb' regex='w{3}' />
</BBB>
</child>
</ChildElements>
</Root>
you can validate your XML with an online XML Validator